1 # Basic test for optimizer trace
3 --source include/have_optimizer_trace.inc
5 # This test gives different results when ps-protocol is enabled
6 # because in ps-protocol, we read OPTIMIZER_TRACE after
7 # 'EXECUTE stmt'; for subqueries the IN->EXISTS transformation is done
8 # at PREPARE time, and not re-done at EXECUTE time, so in normal
9 # protocol the trace talks about IN->EXISTS, but in ps-protocol it
10 # doesn't (as it's the EXECUTE trace and IN->EXISTS was done once for
11 # all at PREPARE; we see IN->EXISTS if we look at the trace of
13 # That's why we have two result files.
14 # This test is skipped in view-protocol because this changes queries
15 # submitted to the optimizer (from 'SELECT x FROM ... WHERE ... etc'
16 # to 'SELECT x FROM mysqltest_tmp_v') so changes trace.
17 # It's also skipped in sp-protocol for the same reason (SELECT becomes
20 # When adding tests here, try to have some of them use SELECT and
21 # others use EXPLAIN SELECT, to verify that both ways give sufficient
25 select * from information_schema.OPTIMIZER_TRACE;
27 let $DEFAULT_TRACE_MEM_SIZE=1048576; # 1MB
28 eval
set optimizer_trace_max_mem_size=$DEFAULT_TRACE_MEM_SIZE;
29 set @@session.optimizer_trace=
"enabled=on";
31 select * from information_schema.OPTIMIZER_TRACE;
33 CREATE
TABLE t5 (c
int);
34 INSERT INTO t5 VALUES (NULL);
37 INSERT INTO t6 VALUES (NULL),(NULL);
39 SELECT (SELECT 1 FROM t6 WHERE d = c) AS RESULT FROM t5 ;
41 # some float values might not be identical on all platforms, we will see.
42 select * from information_schema.OPTIMIZER_TRACE;
43 # check frequency of spaces
44 select (1-length(
replace(TRACE,
" ",
""))/length(TRACE))*100
45 from information_schema.OPTIMIZER_TRACE;
48 set optimizer_trace=
"one_line=on";
49 SELECT (SELECT 1 FROM t6 WHERE d = c) AS RESULT FROM t5 ;
50 select * from information_schema.OPTIMIZER_TRACE;
51 # check frequency of spaces
52 select (1-length(
replace(TRACE,
" ",
""))/length(TRACE))*100
53 from information_schema.OPTIMIZER_TRACE;
55 # From now on, use end markers, easier to read
56 set end_markers_in_json=on;
57 set optimizer_trace=
"one_line=off";
59 # trace should be produced by EXPLAIN too
60 EXPLAIN SELECT (SELECT 1 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5 ;
61 select * from information_schema.OPTIMIZER_TRACE;
63 SELECT (SELECT 1 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5 ;
64 select * from information_schema.OPTIMIZER_TRACE;
66 set @@session.optimizer_trace="enabled=off";
67 SELECT (SELECT 1 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5 ;
68 # should not see last statement but previous
69 select QUERY from information_schema.OPTIMIZER_TRACE;
71 set @@session.optimizer_trace=
"enabled=on";
74 SELECT (SELECT 1 FROM t6 WHERE d = ifnull(c,null) UNION SELECT 2 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5 ;
75 select * from information_schema.OPTIMIZER_TRACE;
77 # union in subquery in WHERE clause
78 SELECT * FROM t5 WHERE 5 IN (SELECT 1 FROM t6 WHERE d = ifnull(c,null) UNION SELECT 2 FROM t6 WHERE d = ifnull(c,null));
79 select * from information_schema.OPTIMIZER_TRACE;
81 # Test max_mem_size: re-run same query with lower max_mem_size:
82 # save non-truncated trace but don't output it again
83 select (@
query:=QUERY)+NULL, (@trace:=TRACE)+NULL from information_schema.OPTIMIZER_TRACE;
84 select length(@trace);
85 # The concatenation of query and trace above has length:
86 # - >@max_mem_size in normal mode
87 # - <@max_mem_size in ps-protocol mode (because IN->EXISTS is done at PREPARE
88 # and we trace only EXECUTE)
89 # - So in normal mode, the lines below verify truncation,
90 # whereas in ps-protocol mode they verify non-truncation.
91 set @max_mem_size=13900;
92 set optimizer_trace_max_mem_size=@max_mem_size;
93 select length(@
query)+length(@trace) > @@optimizer_trace_max_mem_size;
94 SELECT * FROM t5 WHERE 5 IN (SELECT 1 FROM t6 WHERE d = ifnull(c,null) UNION SELECT 2 FROM t6 WHERE d = ifnull(c,null));
95 select (@missing_bytes:=missing_bytes_beyond_max_mem_size) from information_schema.OPTIMIZER_TRACE;
96 select (@query2:=QUERY)+NULL,(@trace2:=TRACE)+NULL from information_schema.OPTIMIZER_TRACE;
97 select length(@trace2),
98 (length(@trace2) + @missing_bytes) = length(@trace),
100 # If truncated, trace length should be around the maximum, possibly a
101 # bit higher as we stop tracing after passing the maximum.
102 select length(@query2) + length(@trace2)
103 between (@@optimizer_trace_max_mem_size-200) and (@@optimizer_trace_max_mem_size+200);
104 # if truncated, trace should be a prefix of non-truncated trace
105 select instr(@trace, @trace2) = 1;
107 # Test that if the query is longer than max size, trace is not produced
108 set optimizer_trace_max_mem_size=1;
110 select * from information_schema.OPTIMIZER_TRACE;
111 # Test that with max size == 0, even query is not produced
112 set optimizer_trace_max_mem_size=0;
114 select * from information_schema.OPTIMIZER_TRACE;
115 eval
set optimizer_trace_max_mem_size=$DEFAULT_TRACE_MEM_SIZE;
119 explain SELECT c FROM t5 where c+1 in (select d+1 from t6 where d is null);
120 select * from information_schema.OPTIMIZER_TRACE;
122 # subquery materialization
124 set @old_opt_switch=@@optimizer_switch;
125 # The SET below must not be output, because only servers supporting
126 # semijoin will execute it (would make varying output).
127 if (`select locate(
'semijoin', @@optimizer_switch) > 0`)
130 set optimizer_switch=
"semijoin=off,subquery_materialization_cost_based=off";
133 explain SELECT c FROM t5 where c+1 in (select d+1 from t6 where d is null);
134 select * from information_schema.OPTIMIZER_TRACE;
135 set optimizer_switch=@old_opt_switch;
137 # 5.1-style subquery transformations
138 CREATE
TABLE t1 (s1 CHAR(5),
140 INSERT INTO t1 VALUES (
'z',
'?'),(
'y',
'!');
142 explain extended select * from t1 where s1 > any (select s2 from t1);
143 select * from information_schema.OPTIMIZER_TRACE;
144 explain extended select * from t1 where s1 > any (select max(s2) from t1);
145 select * from information_schema.OPTIMIZER_TRACE;
147 if (`select locate(
'semijoin', @@optimizer_switch) > 0`)
150 set optimizer_switch=
"semijoin=off,materialization=off";
153 explain extended select * from t1 where s1 in (select s2 from t1);
154 select * from information_schema.OPTIMIZER_TRACE;
155 explain extended select * from t1 where (s1,s2) in (select s2,s1 from t1);
156 select * from information_schema.OPTIMIZER_TRACE;
157 set optimizer_switch=@old_opt_switch;
160 # explanation of plan choice
161 create
table t1(a
int);
162 create
table t2(a
int);
163 insert into t1 values(1),(2),(3);
164 insert into t2 values(1),(2);
166 set @@session.optimizer_prune_level=0;
167 explain select * from t1,t2;
168 select * from information_schema.OPTIMIZER_TRACE;
170 select @@optimizer_trace_features;
171 set @@optimizer_trace_features=
"greedy_search=off";
172 explain select * from t1,t2;
173 select * from information_schema.OPTIMIZER_TRACE;
174 set @@optimizer_trace_features=
default;
175 set @@session.optimizer_prune_level=
default;
178 # test late decision to abandon subquery materialization due to BLOBs
179 # (from subselect_mat.test)
180 # force materialization to be always considered
181 if (`select locate(
'semijoin', @@optimizer_switch) > 0`)
184 set @@optimizer_switch=
'semijoin=off';
188 # BLOB == 16 (small blobs that could be stored in HEAP tables)
190 set @suffix_len = @blob_len - @prefix_len;
191 create
table t1_16 (a1 blob(16), a2 blob(16));
192 create
table t2_16 (b1 blob(16), b2 blob(16));
193 create
table t3_16 (c1 blob(16), c2 blob(16));
194 insert into t1_16 values
195 (concat(
'1 - 00', repeat(
'x', @suffix_len)), concat(
'2 - 00', repeat(
'x', @suffix_len)));
196 insert into t1_16 values
197 (concat(
'1 - 01', repeat(
'x', @suffix_len)), concat(
'2 - 01', repeat(
'x', @suffix_len)));
198 insert into t1_16 values
199 (concat(
'1 - 02', repeat(
'x', @suffix_len)), concat(
'2 - 02', repeat(
'x', @suffix_len)));
200 insert into t2_16 values
201 (concat(
'1 - 01', repeat(
'x', @suffix_len)), concat(
'2 - 01', repeat(
'x', @suffix_len)));
202 insert into t2_16 values
203 (concat(
'1 - 02', repeat(
'x', @suffix_len)), concat(
'2 - 02', repeat(
'x', @suffix_len)));
204 insert into t2_16 values
205 (concat(
'1 - 03', repeat(
'x', @suffix_len)), concat(
'2 - 03', repeat(
'x', @suffix_len)));
206 insert into t3_16 values
207 (concat(
'1 - 01', repeat(
'x', @suffix_len)), concat(
'2 - 01', repeat(
'x', @suffix_len)));
208 insert into t3_16 values
209 (concat(
'1 - 02', repeat(
'x', @suffix_len)), concat(
'2 - 02', repeat(
'x', @suffix_len)));
210 insert into t3_16 values
211 (concat(
'1 - 03', repeat(
'x', @suffix_len)), concat(
'2 - 03', repeat(
'x', @suffix_len)));
212 insert into t3_16 values
213 (concat(
'1 - 04', repeat(
'x', @suffix_len)), concat(
'2 - 04', repeat(
'x', @suffix_len)));
214 # single value transformer
215 explain extended select left(a1,7), left(a2,7)
217 where a1 in (select b1 from t2_16 where b1 > '0');
218 select * from information_schema.OPTIMIZER_TRACE;
219 drop
table t1_16,t2_16,t3_16;
220 set @@optimizer_switch=@old_opt_switch;
222 # test of outer-join preventing semijoin
223 # from subselect.test
225 CREATE
table t1 ( c1 integer );
226 INSERT INTO t1 VALUES ( 1 );
227 INSERT INTO t1 VALUES ( 2 );
228 INSERT INTO t1 VALUES ( 3 );
230 CREATE
TABLE t2 ( c2 integer );
231 INSERT INTO t2 VALUES ( 1 );
232 INSERT INTO t2 VALUES ( 4 );
233 INSERT INTO t2 VALUES ( 5 );
235 SELECT * FROM t1 LEFT
JOIN t2 ON c1 = c2
236 WHERE c2 IN ( SELECT c2 FROM t2 WHERE c2 IN ( 1 ) );
237 select * from information_schema.OPTIMIZER_TRACE;
241 SELECT * FROM t1 WHERE c1=5 UNION SELECT * FROM t2 WHERE c2=5;
242 select * from information_schema.OPTIMIZER_TRACE;
244 # two subqueries in top query
246 if (`select locate(
'semijoin', @@optimizer_switch) > 0`)
249 set optimizer_switch=
"semijoin=off";
255 where concat(c1,
'x') IN
256 (select left(c2,8) from t2)
259 (select left(c2,9) from t2);
261 select * from information_schema.OPTIMIZER_TRACE;
263 set optimizer_switch=@old_opt_switch;
267 # two constant tables
269 create
table t1 (a
int);
270 insert into t1 values(1);
271 create
table t2 (a
int);
272 insert into t2 values(1);
274 select * from information_schema.OPTIMIZER_TRACE;
278 create
table t3 (a
int, b
int);
279 create
table t4 (a
int primary key);
280 insert into t4 values(1),(2);
281 # we do it with prepared statements; by reading the expanded query we
283 # - subquery->semijoin transformation is done at first EXECUTE
284 # - same for semijoin table pullout
285 # - both are reused by the second EXECUTE (where expanded_query is a
287 prepare stmt from
'select * from t3 where (a,a,b) in (select * from t1,t2,t4)';
288 select trace from information_schema.OPTIMIZER_TRACE;
290 select trace from information_schema.OPTIMIZER_TRACE;
292 select trace from information_schema.OPTIMIZER_TRACE;
293 DROP
TABLE t1,t2,t3,t4;
297 create
table t1(a
int);
298 insert into t1 values(1),(1);
299 create
table t2(a
int);
300 insert into t2 values(1),(1);
301 # guarded pushed down conds for WHERE and ON in LEFT JOIN
302 select * from t1 left join t2 on t2.a=500 where t2.a is NULL;
303 select * from information_schema.OPTIMIZER_TRACE;
305 # guarded added conds for IN->EXISTS:
306 create
table t1(a
int, b
int);
307 insert into t1 values(1,NULL),(NULL,2);
308 create
table t2(c
int, d
int);
309 insert into t2 values(1,1),(2,2);
310 select * from t1 where (t1.a,t1.b) not in (select c,d from t2 where c>0);
311 select * from information_schema.OPTIMIZER_TRACE;
314 select t1.a,avg(t2.c) as moyenne from t1, t2 where t2.c>-1
315 group by t1.a having moyenne<>0;
316 --replace_regex /("sort_buffer_size":) [0-9]+/\1 "NNN"/
317 select trace from information_schema.OPTIMIZER_TRACE;
319 select t1.a,avg(t2.c) as moyenne from t1, t2 where t2.c>-1
320 group by t1.a having 4=5;
321 select trace from information_schema.OPTIMIZER_TRACE;
327 # test non-SELECT statements
329 update t6
set d=5 where d is NULL;
330 select * from information_schema.OPTIMIZER_TRACE;
332 delete from t6 where d=5;
333 select * from information_schema.OPTIMIZER_TRACE;
335 insert into t6 values(6),(7),(8);
336 select * from information_schema.OPTIMIZER_TRACE;
338 insert into t6 select * from t6 where d>7;
339 select * from information_schema.OPTIMIZER_TRACE;
341 update t5, t6
set t6.d=t6.d+t5.c+4-t5.c-4 where d>7000;
342 select * from information_schema.OPTIMIZER_TRACE;
344 delete t6 from t5, t6 where d>7000;
345 select * from information_schema.OPTIMIZER_TRACE;
347 # Test optimizer_trace_offset/limit for consecutive
348 # non-related statements (as opposed to "for sub-statements"
349 # which is tested further below).
350 set optimizer_trace_offset=2,optimizer_trace_limit=2;
352 select * from information_schema.OPTIMIZER_TRACE;
358 # In normal mode, each SELECT is a standalone statement and generates
359 # one trace: so 3rd and 4th trace means 3rd and 4th SELECT.
360 # In ps-protocol mode, each SELECT is two statements: PREPARE and
361 # EXECUTE; each of the two creates one trace; so 3rd and 4th trace
362 # means 2nd SELECT (preparation) and 2nd SELECT again (execution).
363 select * from information_schema.OPTIMIZER_TRACE;
364 set optimizer_trace_offset=-2,optimizer_trace_limit=2;
366 select * from information_schema.OPTIMIZER_TRACE;
372 select * from information_schema.OPTIMIZER_TRACE;
373 set optimizer_trace_offset=
default,optimizer_trace_limit=
default;
375 select * from information_schema.OPTIMIZER_TRACE;
377 # For stored functions, stored procedures, triggers, with
378 # offset=-1,limit=1, what we see in the trace is the trace of the last
379 # statement (i.e. last call to mysql_execute_command()). Thus:
380 # - for a call to a stored procedure, we will see only the last
381 # statement of this procedure
382 # - for a call to a trigger, we will see only the last statement of
383 # this trigger, and not the caller.
385 # If the user wants to see more, 'offset' should be adjusted.
390 id char(16) not null
default '',
399 insert into t1 values (
"a", 1), (
"b", 2) |
400 insert into t2 values (
"a", 1, 1.0), (
"b", 2, 2.0), (
"c", 3, 3.0) |
401 create
function f1() returns
int
404 insert into t1 values("z",0);
405 delete from t1 where
id="z";
406 select sum(data) into
ret from t1;
410 # Here we will see the trace of RETURN.
411 select * from information_schema.OPTIMIZER_TRACE|
412 select s, f1() from t2 order by s desc|
413 select * from information_schema.OPTIMIZER_TRACE|
414 select * from t6 where d in (select f1() from t2 where s="c")|
415 select * from information_schema.OPTIMIZER_TRACE|
416 # Want to see the top and invoked sub-statements; this means 11 traces:
417 # 1 top statement + two executions of f1() (there is one
418 # execution inside the range optimizer and one "normal" execution);
419 # in the stored function we have traces: DECLARE (1 trace), 3 DMLs
420 # and RETURN (1 trace). 1+2*(1+3+1)=11.
421 # In ps-protocol mode, we have those 11, plus one for PREPARE of the
423 # We ask for a larger number (60) and will check how many we got.
424 # Note that when semijoin features are disabled, the subquery is
425 # treated differently: it is executed, so the order and amount of
426 # executions of f1() becomes different, which changes the order of
427 # substatements in the trace.
428 set @old_opt_switch=@@optimizer_switch;
429 # Test was created when sj-mat-scan could not handle this query...
430 set optimizer_switch=
"materialization=off";
431 set optimizer_trace_offset=-60, optimizer_trace_limit=60|
432 select * from t6 where d in (select f1() from t2 where s=
"c")|
433 select * from information_schema.OPTIMIZER_TRACE|
434 select count(*) from information_schema.OPTIMIZER_TRACE|
435 # Want to see the DELETE (invoked sub-statement):
436 set optimizer_trace_offset=3, optimizer_trace_limit=1|
437 select * from t6 where d in (select f1() from t2 where s=
"c")|
438 # In normal mode, we have traces for the top SELECT, then the
439 # function's INSERT then the function's DELETE, so DELETE is the
440 # third trace, which we see.
441 # In ps-protocol mode, we also have trace of PREPARE for the top
442 # SELECT, so we see one trace before the DELETE: the INSERT.
443 select * from information_schema.OPTIMIZER_TRACE|
444 set @@optimizer_switch=@old_opt_switch;
447 create procedure p1(arg
char(1))
450 select d into res from t6 where d in (select f1() from t2 where s=arg);
451 select d+1 into res from t6 where d=res+1;
453 set @old_opt_switch=@@optimizer_switch;
454 # Test was created when sj-mat-scan could not handle this query...
455 set optimizer_switch=
"materialization=off";
456 set optimizer_trace_offset=0, optimizer_trace_limit=100;
458 select * from information_schema.OPTIMIZER_TRACE|
459 set @@optimizer_switch=@old_opt_switch;
462 create trigger trg1 before insert on t2
for each row
466 set optimizer_trace_offset=0, optimizer_trace_limit=100|
467 insert into t2 select d,100,200 from t6 where d is not null|
468 select * from information_schema.OPTIMIZER_TRACE|
472 # PREPARE/EXECUTE/EXECUTE
473 prepare stmt from
'select count(*) from t1 where t1.data=?';
475 set optimizer_trace_offset=0, optimizer_trace_limit=100;
476 execute stmt
using @param;
477 select count(*) from information_schema.OPTIMIZER_TRACE;
478 select TRACE into @trace from information_schema.OPTIMIZER_TRACE;
480 # second EXECUTE should give same trace
481 set optimizer_trace_offset=0, optimizer_trace_limit=100;
482 execute stmt
using @param;
483 select count(*) from information_schema.OPTIMIZER_TRACE;
484 select TRACE into @trace2 from information_schema.OPTIMIZER_TRACE;
485 select @trace=@trace2;
487 # enable/disable tracing in middle of procedure
489 create temporary
table optt like information_schema.OPTIMIZER_TRACE;
491 create procedure p1(arg
char(1))
494 set optimizer_trace="enabled=off";
495 # want to see all of SELECT below
496 set optimizer_trace_offset=0, optimizer_trace_limit=100;
497 set optimizer_trace=
"enabled=on";
498 select d into res from t6 where d in (select f1() from t2 where s=arg);
499 set optimizer_trace=
"enabled=off"; # and not more
500 insert into optt select * from information_schema.OPTIMIZER_TRACE;
501 set optimizer_trace_offset=
default, optimizer_trace_limit=
default;
502 select d+1 into res from t6 where d=res+1;
506 select @@optimizer_trace|
509 set optimizer_trace=
"enabled=on";
510 drop temporary
table optt;
517 create
view v1 as select * from t1 where
id <
"c";
518 explain select * from v1 where
id=
"b";
519 select * from information_schema.OPTIMIZER_TRACE;
521 insert into v1 values(
"z", 100);
522 select * from information_schema.OPTIMIZER_TRACE;
523 delete from v1 where data=100;
524 select * from information_schema.OPTIMIZER_TRACE;
527 create
view v1 as select * from t1 where
id <
"c" limit 2;
528 explain select * from v1 where
id=
"b";
529 select * from information_schema.OPTIMIZER_TRACE;
533 select * from information_schema.session_variables where
534 VARIABLE_NAME=
"optimizer_trace";
535 select * from information_schema.OPTIMIZER_TRACE;
537 # test that DUMPFILE does no escaping of \n
538 # otherwise a JSON parser could not read
539 set end_markers_in_json=off;
540 select 1
union select 2;
541 --let $file=$MYSQLTEST_VARDIR/tmp/optimizer_trace.txt
542 --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
543 --eval select TRACE into dumpfile
'$file' from information_schema.OPTIMIZER_TRACE;
544 # it has been manually checked that this file's content is JSON-compliant
548 # Test for crashing bug
549 --error ER_WRONG_VALUE_FOR_VAR
550 set optimizer_switch=
'default,index_merge=on,index_merge=off,default';
551 select @@optimizer_switch=@old_opt_switch;
553 # Test for long query (1070 chars)
556 select
"abc1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111def" as col;
559 select * from information_schema.OPTIMIZER_TRACE;
563 set optimizer_trace=
default;