Skip to content

Commit aa86367

Browse files
author
Guilhem Bichot
committed
Optimizer trace.
By me: WL#5257 Create a first API for the Optimizer trace By Jorgen Loland: WL#5594 Add optimizer traces to the range optimizer WL#5741 Ensure optimizer tracing for subqueries works without JSON syntax errors WL#5581 Add --opt-trace-protocol to MTR. Summary below. * This feature produces a trace for any SELECT/INSERT/UPDATE/DELETE/DO/SET/CALL, which contains information about decisions taken by the optimizer during the optimization phase (choice of table access method, various costs, transformations, etc). It should help understand the logic followed by the optimizer for a particular query. Trace is session-local, controlled by the @@optimizer_trace variable and other new variables, and readable by selecting from information_schema.optimizer_trace. See the doxygen comments in opt_trace.h for more info. * By default the tracing code is compiled in, but not enabled at runtime; set @@optimizer_trace to enable it. * Changes to test results: unless otherwise noted they are due to those changes: ** The query printed by EXPLAIN EXTENDED now shows the id of each SELECT, to help interpret the "id" column. ** EXPLAIN EXTENDED now prints triggered conditions as: trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t2`.`s1`), true) instead of: trigcond(<is_not_null_test>(`test`.`t2`.`s1`). * @@optimizer_trace_offset is a signed variable, so I had to add support for this in MySQL (so far all integer system variables were unsigned, it was impossible to set a system variable to a negative value, it would be rounded to 0).
1 parent 2a23d0f commit aa86367

File tree

254 files changed

+80120
-2963
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

254 files changed

+80120
-2963
lines changed

.bzrignore

+1
Original file line numberDiff line numberDiff line change
@@ -3116,6 +3116,7 @@ libmysqld/transaction.cc
31163116
libmysqld/sys_vars.cc
31173117
libmysqld/keycaches.cc
31183118
client/dtoa.c
3119+
libmysqld/opt_trace.cc
31193120
libmysqld/sql_audit.cc
31203121
storage/archive/archive_performance
31213122
storage/archive/concurrency_test

CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@ MARK_AS_ADVANCED(ENABLED_LOCAL_INFILE)
186186
OPTION(WITH_FAST_MUTEXES "Compile with fast mutexes" OFF)
187187
MARK_AS_ADVANCED(WITH_FAST_MUTEXES)
188188

189+
OPTION(OPTIMIZER_TRACE "Support tracing of Optimizer" ON)
190+
189191
# Set DBUG_OFF and other optional release-only flags for non-debug project types
190192
FOREACH(BUILD_TYPE RELEASE RELWITHDEBINFO MINSIZEREL)
191193
FOREACH(LANG C CXX)

client/mysqltest.cc

+55-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ enum {
9090
OPT_PS_PROTOCOL=OPT_MAX_CLIENT_OPTION, OPT_SP_PROTOCOL,
9191
OPT_CURSOR_PROTOCOL, OPT_VIEW_PROTOCOL, OPT_MAX_CONNECT_RETRIES,
9292
OPT_MAX_CONNECTIONS, OPT_MARK_PROGRESS, OPT_LOG_DIR,
93-
OPT_TAIL_LINES, OPT_RESULT_FORMAT_VERSION, OPT_EXPLAIN_PROTOCOL
93+
OPT_TAIL_LINES, OPT_RESULT_FORMAT_VERSION, OPT_TRACE_PROTOCOL,
94+
OPT_EXPLAIN_PROTOCOL
9495
};
9596

9697
static int record= 0, opt_sleep= -1;
@@ -110,6 +111,7 @@ static my_bool opt_mark_progress= 0;
110111
static my_bool ps_protocol= 0, ps_protocol_enabled= 0;
111112
static my_bool sp_protocol= 0, sp_protocol_enabled= 0;
112113
static my_bool view_protocol= 0, view_protocol_enabled= 0;
114+
static my_bool opt_trace_protocol= 0, opt_trace_protocol_enabled= 0;
113115
static my_bool explain_protocol= 0, explain_protocol_enabled= 0;
114116
static my_bool cursor_protocol= 0, cursor_protocol_enabled= 0;
115117
static my_bool parsing_disabled= 0;
@@ -201,6 +203,8 @@ static char *opt_plugin_dir= 0;
201203
static my_regex_t ps_re; /* the query can be run using PS protocol */
202204
static my_regex_t sp_re; /* the query can be run as a SP */
203205
static my_regex_t view_re; /* the query can be run as a view*/
206+
/* the query can be traced with optimizer trace*/
207+
static my_regex_t opt_trace_re;
204208
static my_regex_t explain_re;/* the query can be converted to EXPLAIN */
205209

206210
static void init_re(void);
@@ -6392,6 +6396,10 @@ static struct my_option my_long_options[] =
63926396
{"view-protocol", OPT_VIEW_PROTOCOL, "Use views for select.",
63936397
&view_protocol, &view_protocol, 0,
63946398
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
6399+
{"opt-trace-protocol", OPT_TRACE_PROTOCOL,
6400+
"Trace DML statements with optimizer trace",
6401+
&opt_trace_protocol, &opt_trace_protocol, 0,
6402+
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
63956403
{"explain-protocol", OPT_EXPLAIN_PROTOCOL,
63966404
"Explain all SELECT/INSERT/REPLACE/UPDATE/DELETE statements",
63976405
&explain_protocol, &explain_protocol, 0,
@@ -7879,6 +7887,40 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags)
78797887
DBUG_VOID_RETURN;
78807888
}
78817889

7890+
/**
7891+
Display the optimizer trace produced by the last executed statement.
7892+
*/
7893+
void display_opt_trace(struct st_connection *cn,
7894+
struct st_command *command,
7895+
int flags)
7896+
{
7897+
if (!disable_query_log &&
7898+
opt_trace_protocol_enabled &&
7899+
!command->expected_errors.count &&
7900+
match_re(&opt_trace_re, command->query))
7901+
{
7902+
st_command save_command= *command;
7903+
DYNAMIC_STRING query_str;
7904+
init_dynamic_string(&query_str,
7905+
"SELECT trace FROM information_schema.optimizer_trace"
7906+
" /* injected by --opt-trace-protocol */",
7907+
128, 128);
7908+
7909+
command->query= query_str.str;
7910+
command->query_len= query_str.length;
7911+
command->end= strend(command->query);
7912+
7913+
/* sorted trace is not readable at all*/
7914+
my_bool save_display_result_sorted= display_result_sorted;
7915+
display_result_sorted= FALSE;
7916+
run_query(cn, command, flags);
7917+
display_result_sorted= save_display_result_sorted;
7918+
7919+
dynstr_free(&query_str);
7920+
*command= save_command;
7921+
}
7922+
}
7923+
78827924

78837925
void run_explain(struct st_connection *cn, struct st_command *command, int flags)
78847926
{
@@ -7968,6 +8010,13 @@ void init_re(void)
79688010
"^("
79698011
"[[:space:]]*SELECT[[:space:]])";
79708012

8013+
const char *opt_trace_re_str =
8014+
"^("
8015+
"[[:space:]]*INSERT[[:space:]]|"
8016+
"[[:space:]]*UPDATE[[:space:]]|"
8017+
"[[:space:]]*DELETE[[:space:]]|"
8018+
"[[:space:]]*EXPLAIN[[:space:]]|"
8019+
"[[:space:]]*SELECT[[:space:]])";
79718020

79728021
/* Filter for queries that can be converted to EXPLAIN */
79738022
const char *explain_re_str =
@@ -7977,6 +8026,7 @@ void init_re(void)
79778026
init_re_comp(&ps_re, ps_re_str);
79788027
init_re_comp(&sp_re, sp_re_str);
79798028
init_re_comp(&view_re, view_re_str);
8029+
init_re_comp(&opt_trace_re, opt_trace_re_str);
79808030
init_re_comp(&explain_re, explain_re_str);
79818031
}
79828032

@@ -8014,6 +8064,7 @@ void free_re(void)
80148064
my_regfree(&ps_re);
80158065
my_regfree(&sp_re);
80168066
my_regfree(&view_re);
8067+
my_regfree(&opt_trace_re);
80178068
my_regex_end();
80188069
}
80198070

@@ -8327,6 +8378,7 @@ int main(int argc, char **argv)
83278378
var_set_int("$PS_PROTOCOL", ps_protocol);
83288379
var_set_int("$SP_PROTOCOL", sp_protocol);
83298380
var_set_int("$VIEW_PROTOCOL", view_protocol);
8381+
var_set_int("$OPT_TRACE_PROTOCOL", opt_trace_protocol);
83308382
var_set_int("$EXPLAIN_PROTOCOL", explain_protocol);
83318383
var_set_int("$CURSOR_PROTOCOL", cursor_protocol);
83328384

@@ -8363,6 +8415,7 @@ int main(int argc, char **argv)
83638415
ps_protocol_enabled= ps_protocol;
83648416
sp_protocol_enabled= sp_protocol;
83658417
view_protocol_enabled= view_protocol;
8418+
opt_trace_protocol_enabled= opt_trace_protocol;
83668419
explain_protocol_enabled= explain_protocol;
83678420
cursor_protocol_enabled= cursor_protocol;
83688421

@@ -8649,6 +8702,7 @@ int main(int argc, char **argv)
86498702
*/
86508703
run_explain(cur_con, command, flags);
86518704
run_query(cur_con, command, flags);
8705+
display_opt_trace(cur_con, command, flags);
86528706
command_executed++;
86538707
command->last_argument= command->end;
86548708

config.h.cmake

+1
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,7 @@
511511
#cmakedefine EXTRA_DEBUG 1
512512
#cmakedefine BACKUP_TEST 1
513513
#cmakedefine CYBOZU 1
514+
#cmakedefine OPTIMIZER_TRACE 1
514515
#cmakedefine USE_SYMDIR 1
515516

516517
/* Character sets and collations */

dbug/dbug.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -1412,7 +1412,7 @@ static struct link *ListAddDel(struct link *head, const char *ctlp,
14121412
}
14131413
else
14141414
{
1415-
(*cur)->flags&=~(EXCLUDE & SUBDIR);
1415+
(*cur)->flags&=~(EXCLUDE | SUBDIR);
14161416
(*cur)->flags|=INCLUDE | subdir;
14171417
}
14181418
goto next;

include/my_getopt.h

+1
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ longlong getopt_ll_limit_value(longlong, const struct my_option *,
116116
double getopt_double_limit_value(double num, const struct my_option *optp,
117117
my_bool *fix);
118118
my_bool getopt_compare_strings(const char *s, const char *t, uint length);
119+
ulonglong max_of_int_range(int var_type);
119120

120121
C_MODE_END
121122

include/my_sys.h

+20-5
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,22 @@ extern void *my_memdup(const void *from,size_t length,myf MyFlags);
158158
extern char *my_strdup(const char *from,myf MyFlags);
159159
extern char *my_strndup(const char *from, size_t length,
160160
myf MyFlags);
161-
#define TRASH(A,B) do{MEM_CHECK_ADDRESSABLE(A,B);MEM_UNDEFINED(A,B);} while (0)
161+
#if !defined(DBUG_OFF) || defined(HAVE_VALGRIND)
162+
/**
163+
Put bad content in memory to be sure it will segfault if dereferenced.
164+
With Valgrind, verify that memory is addressable, and mark it undefined.
165+
We cache value of B because if B is expression which depends on A, memset()
166+
trashes value of B.
167+
*/
168+
#define TRASH(A,B) do { \
169+
const size_t l= (B); \
170+
MEM_CHECK_ADDRESSABLE(A, l); \
171+
memset(A, 0x8F, l); \
172+
MEM_UNDEFINED(A, l); \
173+
} while (0)
174+
#else
175+
#define TRASH(A,B) do {} while(0)
176+
#endif
162177
#if defined(ENABLED_DEBUG_SYNC)
163178
extern void (*debug_sync_C_callback_ptr)(const char *, size_t);
164179
#define DEBUG_SYNC_C(_sync_point_name_) do { \
@@ -763,16 +778,16 @@ extern my_bool init_dynamic_array2(DYNAMIC_ARRAY *array, uint element_size,
763778
extern my_bool init_dynamic_array(DYNAMIC_ARRAY *array, uint element_size,
764779
uint init_alloc, uint alloc_increment);
765780
extern my_bool insert_dynamic(DYNAMIC_ARRAY *array, const void *element);
766-
extern uchar *alloc_dynamic(DYNAMIC_ARRAY *array);
767-
extern uchar *pop_dynamic(DYNAMIC_ARRAY*);
781+
extern void *alloc_dynamic(DYNAMIC_ARRAY *array);
782+
extern void *pop_dynamic(DYNAMIC_ARRAY*);
768783
extern my_bool set_dynamic(DYNAMIC_ARRAY *array, const void *element,
769784
uint array_index);
770785
extern my_bool allocate_dynamic(DYNAMIC_ARRAY *array, uint max_elements);
771-
extern void get_dynamic(DYNAMIC_ARRAY *array,uchar * element,uint array_index);
786+
extern void get_dynamic(DYNAMIC_ARRAY *array, void *element,
787+
uint array_index);
772788
extern void delete_dynamic(DYNAMIC_ARRAY *array);
773789
extern void delete_dynamic_element(DYNAMIC_ARRAY *array, uint array_index);
774790
extern void freeze_size(DYNAMIC_ARRAY *array);
775-
extern int get_index_dynamic(DYNAMIC_ARRAY *array, uchar * element);
776791
#define dynamic_array_ptr(array,array_index) ((array)->buffer+(array_index)*(array)->size_of_element)
777792
#define dynamic_element(array,array_index,type) ((type)((array)->buffer) +(array_index))
778793
#define push_dynamic(A,B) insert_dynamic((A),(B))

include/mysql/plugin.h

+6-3
Original file line numberDiff line numberDiff line change
@@ -124,13 +124,16 @@ __MYSQL_DECLARE_PLUGIN(NAME, \
124124

125125
#define mysql_declare_plugin_end ,{0,0,0,0,0,0,0,0,0,0,0,0}}
126126

127-
/*
127+
/**
128128
declarations for SHOW STATUS support in plugins
129129
*/
130130
enum enum_mysql_show_type
131131
{
132-
SHOW_UNDEF, SHOW_BOOL, SHOW_INT, SHOW_LONG,
133-
SHOW_LONGLONG, SHOW_CHAR, SHOW_CHAR_PTR,
132+
SHOW_UNDEF, SHOW_BOOL,
133+
SHOW_INT, ///< shown as _unsigned_ int
134+
SHOW_LONG, ///< shown as _unsigned_ long
135+
SHOW_LONGLONG, ///< shown as _unsigned_ longlong
136+
SHOW_CHAR, SHOW_CHAR_PTR,
134137
SHOW_ARRAY, SHOW_FUNC, SHOW_DOUBLE,
135138
SHOW_always_last
136139
};

include/mysql/plugin_audit.h.pp

+5-2
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,11 @@
8282
typedef struct st_mysql_xid MYSQL_XID;
8383
enum enum_mysql_show_type
8484
{
85-
SHOW_UNDEF, SHOW_BOOL, SHOW_INT, SHOW_LONG,
86-
SHOW_LONGLONG, SHOW_CHAR, SHOW_CHAR_PTR,
85+
SHOW_UNDEF, SHOW_BOOL,
86+
SHOW_INT,
87+
SHOW_LONG,
88+
SHOW_LONGLONG,
89+
SHOW_CHAR, SHOW_CHAR_PTR,
8790
SHOW_ARRAY, SHOW_FUNC, SHOW_DOUBLE,
8891
SHOW_always_last
8992
};

include/mysql/plugin_auth.h.pp

+5-2
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,11 @@
8282
typedef struct st_mysql_xid MYSQL_XID;
8383
enum enum_mysql_show_type
8484
{
85-
SHOW_UNDEF, SHOW_BOOL, SHOW_INT, SHOW_LONG,
86-
SHOW_LONGLONG, SHOW_CHAR, SHOW_CHAR_PTR,
85+
SHOW_UNDEF, SHOW_BOOL,
86+
SHOW_INT,
87+
SHOW_LONG,
88+
SHOW_LONGLONG,
89+
SHOW_CHAR, SHOW_CHAR_PTR,
8790
SHOW_ARRAY, SHOW_FUNC, SHOW_DOUBLE,
8891
SHOW_always_last
8992
};

include/mysql/plugin_ftparser.h.pp

+5-2
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,11 @@
8282
typedef struct st_mysql_xid MYSQL_XID;
8383
enum enum_mysql_show_type
8484
{
85-
SHOW_UNDEF, SHOW_BOOL, SHOW_INT, SHOW_LONG,
86-
SHOW_LONGLONG, SHOW_CHAR, SHOW_CHAR_PTR,
85+
SHOW_UNDEF, SHOW_BOOL,
86+
SHOW_INT,
87+
SHOW_LONG,
88+
SHOW_LONGLONG,
89+
SHOW_CHAR, SHOW_CHAR_PTR,
8790
SHOW_ARRAY, SHOW_FUNC, SHOW_DOUBLE,
8891
SHOW_always_last
8992
};

mysql-test/collections/default.experimental

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ main.mysqlslap @windows # Bug#11761520 2010-08-10 alik mysqlsla
1111
main.signal_demo3 @solaris # Bug#11755949 2010-01-20 alik Several test cases fail on Solaris with error Thread stack overrun
1212
main.sp @solaris # Bug#11755949 2010-01-20 alik Several test cases fail on Solaris with error Thread stack overrun
1313
main.subquery_sj_none @solaris # Bug#11755949 2010-01-20 alik Several test cases fail on Solaris with error Thread stack overrun
14+
main.subquery_sj_none_jcl6 @solaris # Bug#11755949 2010-01-20 alik Several test cases fail on Solaris with error Thread stack overrun
15+
main.subquery_sj_none_jcl7 @solaris # Bug#11755949 2010-01-20 alik Several test cases fail on Solaris with error Thread stack overrun
1416
main.wait_timeout @solaris # Bug#11758972 2010-04-26 alik wait_timeout fails on OpenSolaris
1517

1618
rpl.rpl_delayed_slave # BUG#11764654 rpl_delayed_slave fails sporadically in pb
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
--disable_query_log
2+
3+
# Check if variable optimizer_trace exists
4+
let $have_var = `select TRUE from information_schema.session_variables where variable_name="optimizer_trace"`;
5+
if (!$have_var)
6+
{
7+
skip requires optimizer trace support;
8+
}
9+
--enable_query_log

mysql-test/mysql-test-run.pl

+19-2
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ END
163163

164164
# If you add a new suite, please check TEST_DIRS in Makefile.am.
165165
#
166-
my $DEFAULT_SUITES= "main,sys_vars,binlog,federated,rpl,innodb,perfschema,funcs_1";
166+
my $DEFAULT_SUITES= "main,sys_vars,binlog,federated,rpl,innodb,perfschema,funcs_1,optimizer_trace";
167167
my $opt_suites;
168168

169169
our $opt_verbose= 0; # Verbose output, enable with --verbose
@@ -189,6 +189,7 @@ END
189189
my $opt_sp_protocol;
190190
my $opt_cursor_protocol;
191191
my $opt_view_protocol;
192+
my $opt_trace_protocol;
192193
my $opt_explain_protocol;
193194

194195
our $opt_debug;
@@ -1043,6 +1044,7 @@ sub command_line_setup {
10431044
'ps-protocol' => \$opt_ps_protocol,
10441045
'sp-protocol' => \$opt_sp_protocol,
10451046
'view-protocol' => \$opt_view_protocol,
1047+
'opt-trace-protocol' => \$opt_trace_protocol,
10461048
'explain-protocol' => \$opt_explain_protocol,
10471049
'cursor-protocol' => \$opt_cursor_protocol,
10481050
'ssl|with-openssl' => \$opt_ssl,
@@ -1682,6 +1684,13 @@ sub command_line_setup {
16821684
unless @valgrind_args;
16831685
}
16841686

1687+
if ( $opt_trace_protocol )
1688+
{
1689+
push(@opt_extra_mysqld_opt, "--optimizer_trace=enabled=on,one_line=off");
1690+
# some queries yield big traces:
1691+
push(@opt_extra_mysqld_opt, "--optimizer-trace-max-mem-size=1000000");
1692+
}
1693+
16851694
if ( $opt_valgrind )
16861695
{
16871696
# Set valgrind_options to default unless already defined
@@ -5456,6 +5465,11 @@ ($)
54565465
mtr_add_arg($args, "--view-protocol");
54575466
}
54585467

5468+
if ( $opt_trace_protocol )
5469+
{
5470+
mtr_add_arg($args, "--opt-trace-protocol");
5471+
}
5472+
54595473
if ( $opt_cursor_protocol )
54605474
{
54615475
mtr_add_arg($args, "--cursor-protocol");
@@ -5961,6 +5975,7 @@ ($)
59615975
cursor-protocol Use the cursor protocol between client and server
59625976
(implies --ps-protocol)
59635977
view-protocol Create a view to execute all non updating queries
5978+
opt-trace-protocol Print optimizer trace
59645979
explain-protocol Run 'EXPLAIN EXTENDED' on all SELECT queries
59655980
sp-protocol Create a stored procedure to execute all queries
59665981
compress Use the compressed protocol between client and server
@@ -6062,7 +6077,9 @@ ($)
60626077
ddd Start mysqld in ddd
60636078
debug Dump trace output for all servers and client programs
60646079
debug-common Same as debug, but sets 'd' debug flags to
6065-
"query,info,error,enter,exit"
6080+
"query,info,error,enter,exit"; you need this if you
6081+
want both to see debug printouts and to use
6082+
DBUG_EXECUTE_IF.
60666083
debug-server Use debug version of server, but without turning on
60676084
tracing
60686085
debugger=NAME Start mysqld in the selected debugger

0 commit comments

Comments
 (0)