diff --git a/mysql-test/main/opt_hints_split_materialized.result b/mysql-test/main/opt_hints_split_materialized.result new file mode 100644 index 00000000000..9c1b6e9c36b --- /dev/null +++ b/mysql-test/main/opt_hints_split_materialized.result @@ -0,0 +1,781 @@ +# +# MDEV-36092 New-style hint: [NO_]SPLIT_MATERIALIZED +# +set @save_optimizer_switch=@@optimizer_switch; +# +# case 1 +# +create table t1 ( +n1 int(10) not null, +n2 int(10) not null, +c1 char(1) not null, +key c1 (c1), +key n1_c1_n2 (n1,c1,n2) +) engine=innodb charset=latin1; +insert into t1 values (0, 2, 'a'), (1, 3, 'a'); +insert into t1 select seq+1,seq+2,'c' from seq_1_to_1000; +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +# default showing lateral derived optimization in use +explain +select t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ref c1,n1_c1_n2 c1 1 const 2 Using index condition; Using where; Using temporary; Using filesort +1 PRIMARY ref key0 key0 8 test.t1.n1,test.t1.n2 1 +2 LATERAL DERIVED t1 ref c1,n1_c1_n2 n1_c1_n2 4 test.t1.n1 1 Using where; Using index +select t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1; +n1 +0 +1 +# cases where hint disables lateral derived optimization +explain +select /*+ no_split_materialized(t) */ t1.n1 from t1, +(select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ref c1,n1_c1_n2 c1 1 const 2 Using index condition; Using where; Using temporary; Using filesort +1 PRIMARY ref key0 key0 8 test.t1.n1,test.t1.n2 1 +2 DERIVED t1 ref c1 c1 1 const 2 Using index condition; Using where; Using temporary; Using filesort +select /*+ no_split_materialized(t) */ t1.n1 from t1, +(select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1; +n1 +0 +1 +# query having two subqueries, both of which are subject to LATERAL DERIVED optimization +# explain and result without hints +explain +with cte as ( +select t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select * from cte; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL NULL NULL NULL NULL 4 +2 DERIVED t1 ref c1,n1_c1_n2 c1 1 const 2 Using index condition; Using where; Using temporary; Using filesort +2 DERIVED ref key0 key0 8 test.t1.n1,test.t1.n2 1 +3 LATERAL DERIVED t1 ref c1,n1_c1_n2 n1_c1_n2 4 test.t1.n1 1 Using where; Using index +4 UNION t1 ref c1,n1_c1_n2 c1 1 const 2 Using index condition; Using where; Using temporary; Using filesort +4 UNION ref key0 key0 8 test.t1.n1,test.t1.n2 1 +5 LATERAL DERIVED t1 ref c1,n1_c1_n2 n1_c1_n2 4 test.t1.n1 1 Using where; Using index +NULL UNION RESULT ALL NULL NULL NULL NULL NULL +with cte as ( +select /*+ QB_NAME(qb1) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select /*+ QB_NAME(qb2) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select * from cte; +n1 +0 +1 +# explain and result with first half of query disabling the optimization +explain +with cte as ( +select /*+ QB_NAME(qb1) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select /*+ QB_NAME(qb2) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select /*+ NO_SPLIT_MATERIALIZED(t@qb1) */ * from cte; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL NULL NULL NULL NULL 4 +2 DERIVED t1 ref c1,n1_c1_n2 c1 1 const 2 Using index condition; Using where; Using temporary; Using filesort +2 DERIVED ref key0 key0 8 test.t1.n1,test.t1.n2 1 +3 DERIVED t1 ref c1 c1 1 const 2 Using index condition; Using where; Using temporary; Using filesort +4 UNION t1 ref c1,n1_c1_n2 c1 1 const 2 Using index condition; Using where; Using temporary; Using filesort +4 UNION ref key0 key0 8 test.t1.n1,test.t1.n2 1 +5 LATERAL DERIVED t1 ref c1,n1_c1_n2 n1_c1_n2 4 test.t1.n1 1 Using where; Using index +NULL UNION RESULT ALL NULL NULL NULL NULL NULL +with cte as ( +select /*+ QB_NAME(qb1) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select /*+ QB_NAME(qb2) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select /*+ NO_SPLIT_MATERIALIZED(t@qb1) */ * from cte; +n1 +0 +1 +# explain and result with second half of query disabling the optimization +explain +with cte as ( +select /*+ QB_NAME(qb1) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select /*+ QB_NAME(qb2) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select /*+ NO_SPLIT_MATERIALIZED(t@qb2) */ * from cte; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL NULL NULL NULL NULL 4 +2 DERIVED t1 ref c1,n1_c1_n2 c1 1 const 2 Using index condition; Using where; Using temporary; Using filesort +2 DERIVED ref key0 key0 8 test.t1.n1,test.t1.n2 1 +3 LATERAL DERIVED t1 ref c1,n1_c1_n2 n1_c1_n2 4 test.t1.n1 1 Using where; Using index +4 UNION t1 ref c1,n1_c1_n2 c1 1 const 2 Using index condition; Using where; Using temporary; Using filesort +4 UNION ref key0 key0 8 test.t1.n1,test.t1.n2 1 +5 DERIVED t1 ref c1 c1 1 const 2 Using index condition; Using where; Using temporary; Using filesort +NULL UNION RESULT ALL NULL NULL NULL NULL NULL +with cte as ( +select /*+ QB_NAME(qb1) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select /*+ QB_NAME(qb2) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select /*+ NO_SPLIT_MATERIALIZED(t@qb2) */ * from cte; +n1 +0 +1 +# explain and result with both halves of query disabling the optimization +explain +with cte as ( +select /*+ QB_NAME(qb1) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select /*+ QB_NAME(qb2) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select /*+ NO_SPLIT_MATERIALIZED(t@qb1) NO_SPLIT_MATERIALIZED(t@qb2) */ * from cte; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL NULL NULL NULL NULL 4 +2 DERIVED t1 ref c1,n1_c1_n2 c1 1 const 2 Using index condition; Using where; Using temporary; Using filesort +2 DERIVED ref key0 key0 8 test.t1.n1,test.t1.n2 1 +3 DERIVED t1 ref c1 c1 1 const 2 Using index condition; Using where; Using temporary; Using filesort +4 UNION t1 ref c1,n1_c1_n2 c1 1 const 2 Using index condition; Using where; Using temporary; Using filesort +4 UNION ref key0 key0 8 test.t1.n1,test.t1.n2 1 +5 DERIVED t1 ref c1 c1 1 const 2 Using index condition; Using where; Using temporary; Using filesort +NULL UNION RESULT ALL NULL NULL NULL NULL NULL +with cte as ( +select /*+ QB_NAME(qb1) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select /*+ QB_NAME(qb2) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select /*+ NO_SPLIT_MATERIALIZED(t@qb1) NO_SPLIT_MATERIALIZED(t@qb2) */ * from cte; +n1 +0 +1 +# test opposite way, where hint enables the optimization instead of disabling it +set optimizer_switch='split_materialized=off'; +# default showing lateral derived optimization not used +explain +select t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ref c1,n1_c1_n2 c1 1 const 2 Using index condition; Using where; Using temporary; Using filesort +1 PRIMARY ref key0 key0 8 test.t1.n1,test.t1.n2 1 +2 DERIVED t1 ref c1 c1 1 const 2 Using index condition; Using where; Using temporary; Using filesort +select t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1; +n1 +0 +1 +# cases where hint enables lateral derived optimization +explain +select /*+ split_materialized(t) */ t1.n1 from t1, +(select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ref c1,n1_c1_n2 c1 1 const 2 Using index condition; Using where; Using temporary; Using filesort +1 PRIMARY ref key0 key0 8 test.t1.n1,test.t1.n2 1 +2 LATERAL DERIVED t1 ref c1,n1_c1_n2 n1_c1_n2 4 test.t1.n1 1 Using where; Using index +select /*+ split_materialized(t) */ t1.n1 from t1, +(select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1; +n1 +0 +1 +# query having two subqueries, both of which are subject to LATERAL DERIVED optimization +# explain and result without hints +explain +with cte as ( +select t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select * from cte; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL NULL NULL NULL NULL 4 +2 DERIVED t1 ref c1,n1_c1_n2 c1 1 const 2 Using index condition; Using where; Using temporary; Using filesort +2 DERIVED ref key0 key0 8 test.t1.n1,test.t1.n2 1 +3 DERIVED t1 ref c1 c1 1 const 2 Using index condition; Using where; Using temporary; Using filesort +4 UNION t1 ref c1,n1_c1_n2 c1 1 const 2 Using index condition; Using where; Using temporary; Using filesort +4 UNION ref key0 key0 8 test.t1.n1,test.t1.n2 1 +5 DERIVED t1 ref c1 c1 1 const 2 Using index condition; Using where; Using temporary; Using filesort +NULL UNION RESULT ALL NULL NULL NULL NULL NULL +with cte as ( +select t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select * from cte; +n1 +0 +1 +# explain and result with first half of query enabling the optimization +explain +with cte as ( +select /*+ QB_NAME(qb1) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select /*+ QB_NAME(qb2) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select /*+ SPLIT_MATERIALIZED(t@qb1) */ * from cte; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL NULL NULL NULL NULL 4 +2 DERIVED t1 ref c1,n1_c1_n2 c1 1 const 2 Using index condition; Using where; Using temporary; Using filesort +2 DERIVED ref key0 key0 8 test.t1.n1,test.t1.n2 1 +3 LATERAL DERIVED t1 ref c1,n1_c1_n2 n1_c1_n2 4 test.t1.n1 1 Using where; Using index +4 UNION t1 ref c1,n1_c1_n2 c1 1 const 2 Using index condition; Using where; Using temporary; Using filesort +4 UNION ref key0 key0 8 test.t1.n1,test.t1.n2 1 +5 DERIVED t1 ref c1 c1 1 const 2 Using index condition; Using where; Using temporary; Using filesort +NULL UNION RESULT ALL NULL NULL NULL NULL NULL +with cte as ( +select /*+ QB_NAME(qb1) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select /*+ QB_NAME(qb2) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select /*+ SPLIT_MATERIALIZED(t@qb1) */ * from cte; +n1 +0 +1 +# explain and result with second half of query enabling the optimization +explain +with cte as ( +select /*+ QB_NAME(qb1) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select /*+ QB_NAME(qb2) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select /*+ SPLIT_MATERIALIZED(t@qb2) */ * from cte; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL NULL NULL NULL NULL 4 +2 DERIVED t1 ref c1,n1_c1_n2 c1 1 const 2 Using index condition; Using where; Using temporary; Using filesort +2 DERIVED ref key0 key0 8 test.t1.n1,test.t1.n2 1 +3 DERIVED t1 ref c1 c1 1 const 2 Using index condition; Using where; Using temporary; Using filesort +4 UNION t1 ref c1,n1_c1_n2 c1 1 const 2 Using index condition; Using where; Using temporary; Using filesort +4 UNION ref key0 key0 8 test.t1.n1,test.t1.n2 1 +5 LATERAL DERIVED t1 ref c1,n1_c1_n2 n1_c1_n2 4 test.t1.n1 1 Using where; Using index +NULL UNION RESULT ALL NULL NULL NULL NULL NULL +with cte as ( +select /*+ QB_NAME(qb1) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select /*+ QB_NAME(qb2) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select /*+ SPLIT_MATERIALIZED(t@qb2) */ * from cte; +n1 +0 +1 +# explain and result with both halves of query enabling the optimization +explain +with cte as ( +select /*+ QB_NAME(qb1) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select /*+ QB_NAME(qb2) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select /*+ SPLIT_MATERIALIZED(t@qb1) SPLIT_MATERIALIZED(t@qb2) */ * from cte; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL NULL NULL NULL NULL 4 +2 DERIVED t1 ref c1,n1_c1_n2 c1 1 const 2 Using index condition; Using where; Using temporary; Using filesort +2 DERIVED ref key0 key0 8 test.t1.n1,test.t1.n2 1 +3 LATERAL DERIVED t1 ref c1,n1_c1_n2 n1_c1_n2 4 test.t1.n1 1 Using where; Using index +4 UNION t1 ref c1,n1_c1_n2 c1 1 const 2 Using index condition; Using where; Using temporary; Using filesort +4 UNION ref key0 key0 8 test.t1.n1,test.t1.n2 1 +5 LATERAL DERIVED t1 ref c1,n1_c1_n2 n1_c1_n2 4 test.t1.n1 1 Using where; Using index +NULL UNION RESULT ALL NULL NULL NULL NULL NULL +with cte as ( +select /*+ QB_NAME(qb1) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select /*+ QB_NAME(qb2) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t +where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select /*+ SPLIT_MATERIALIZED(t@qb1) SPLIT_MATERIALIZED(t@qb2) */ * from cte; +n1 +0 +1 +set optimizer_switch=@save_optimizer_switch; +drop table t1; +# +# end case 1 +# +# +# case 2 +# +set @save_optimizer_switch=@@optimizer_switch; +create table t1(a int, b int); +insert into t1 select seq,seq from seq_1_to_5; +create table t2(a int, b int, key(a)); +insert into t2 +select a.seq,b.seq from seq_1_to_25 a, seq_1_to_2 b; +create table t3(a int, b int, key(a)); +insert into t3 +select a.seq,b.seq from seq_1_to_5 a, seq_1_to_3 b; +analyze table t1,t2,t3 persistent for all; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +test.t2 analyze status Engine-independent statistics collected +test.t2 analyze status Table is already up to date +test.t3 analyze status Engine-independent statistics collected +test.t3 analyze status Table is already up to date +create table t10 ( +grp_id int, +col1 int, +key(grp_id) +); +insert into t10 +select +a.seq, +b.seq +from +seq_1_to_100 a, +seq_1_to_100 b; +create table t11 ( +col1 int, +col2 int +); +insert into t11 +select a.seq, a.seq from seq_1_to_10 a; +analyze table t10,t11 persistent for all; +Table Op Msg_type Msg_text +test.t10 analyze status Engine-independent statistics collected +test.t10 analyze status Table is already up to date +test.t11 analyze status Engine-independent statistics collected +test.t11 analyze status OK +create table t21 (pk int primary key); +insert into t21 values (1),(2),(3); +create table t22 (pk int primary key); +insert into t22 values (1),(2),(3); +# default showing lateral derived optimization in use +explain +select * from +t21, +( +(t1 left join t2 on t2.a=t1.b) +left join t3 on t3.a=t1.b +) left join (select grp_id, count(*) +from +t22 join t10 left join t11 on t11.col1=t10.col1 +where +t22.pk=1 +group by grp_id) t on t.grp_id=t1.b +where +t21.pk=1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t21 const PRIMARY PRIMARY 4 const 1 Using index +1 PRIMARY t1 ALL NULL NULL NULL NULL 5 +1 PRIMARY t2 ref a a 5 test.t1.b 2 Using where +1 PRIMARY t3 ref a a 5 test.t1.b 3 Using where +1 PRIMARY ref key0 key0 5 test.t1.b 10 Using where +2 LATERAL DERIVED t22 const PRIMARY PRIMARY 4 const 1 Using index +2 LATERAL DERIVED t10 ref grp_id grp_id 5 test.t1.b 100 +2 LATERAL DERIVED t11 ALL NULL NULL NULL NULL 10 Using where; Using join buffer (flat, BNL join) +select * from +t21, +( +(t1 left join t2 on t2.a=t1.b) +left join t3 on t3.a=t1.b +) left join (select grp_id, count(*) +from +t22 join t10 left join t11 on t11.col1=t10.col1 +where +t22.pk=1 +group by grp_id) t on t.grp_id=t1.b +where +t21.pk=1; +pk a b a b a b grp_id count(*) +1 1 1 1 1 1 1 1 100 +1 1 1 1 1 1 2 1 100 +1 1 1 1 1 1 3 1 100 +1 1 1 1 2 1 1 1 100 +1 1 1 1 2 1 2 1 100 +1 1 1 1 2 1 3 1 100 +1 2 2 2 1 2 1 2 100 +1 2 2 2 1 2 2 2 100 +1 2 2 2 1 2 3 2 100 +1 2 2 2 2 2 1 2 100 +1 2 2 2 2 2 2 2 100 +1 2 2 2 2 2 3 2 100 +1 3 3 3 1 3 1 3 100 +1 3 3 3 1 3 2 3 100 +1 3 3 3 1 3 3 3 100 +1 3 3 3 2 3 1 3 100 +1 3 3 3 2 3 2 3 100 +1 3 3 3 2 3 3 3 100 +1 4 4 4 1 4 1 4 100 +1 4 4 4 1 4 2 4 100 +1 4 4 4 1 4 3 4 100 +1 4 4 4 2 4 1 4 100 +1 4 4 4 2 4 2 4 100 +1 4 4 4 2 4 3 4 100 +1 5 5 5 1 5 1 5 100 +1 5 5 5 1 5 2 5 100 +1 5 5 5 1 5 3 5 100 +1 5 5 5 2 5 1 5 100 +1 5 5 5 2 5 2 5 100 +1 5 5 5 2 5 3 5 100 +# cases where hint disables lateral derived optimization +explain +select /*+ no_split_materialized(t) */ * from +t21, +( +(t1 left join t2 on t2.a=t1.b) +left join t3 on t3.a=t1.b +) left join (select grp_id, count(*) +from +t22 join t10 left join t11 on t11.col1=t10.col1 +where +t22.pk=1 +group by grp_id) t on t.grp_id=t1.b +where +t21.pk=1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t21 const PRIMARY PRIMARY 4 const 1 Using index +1 PRIMARY t1 ALL NULL NULL NULL NULL 5 +1 PRIMARY t2 ref a a 5 test.t1.b 2 Using where +1 PRIMARY t3 ref a a 5 test.t1.b 3 Using where +1 PRIMARY ref key0 key0 5 test.t1.b 10 Using where +2 DERIVED t22 const PRIMARY PRIMARY 4 const 1 Using index; Using temporary; Using filesort +2 DERIVED t10 ALL NULL NULL NULL NULL 10000 +2 DERIVED t11 ALL NULL NULL NULL NULL 10 Using where; Using join buffer (flat, BNL join) +select /*+ no_split_materialized(t) */ * from +t21, +( +(t1 left join t2 on t2.a=t1.b) +left join t3 on t3.a=t1.b +) left join (select grp_id, count(*) +from +t22 join t10 left join t11 on t11.col1=t10.col1 +where +t22.pk=1 +group by grp_id) t on t.grp_id=t1.b +where +t21.pk=1; +pk a b a b a b grp_id count(*) +1 1 1 1 1 1 1 1 100 +1 1 1 1 1 1 2 1 100 +1 1 1 1 1 1 3 1 100 +1 1 1 1 2 1 1 1 100 +1 1 1 1 2 1 2 1 100 +1 1 1 1 2 1 3 1 100 +1 2 2 2 1 2 1 2 100 +1 2 2 2 1 2 2 2 100 +1 2 2 2 1 2 3 2 100 +1 2 2 2 2 2 1 2 100 +1 2 2 2 2 2 2 2 100 +1 2 2 2 2 2 3 2 100 +1 3 3 3 1 3 1 3 100 +1 3 3 3 1 3 2 3 100 +1 3 3 3 1 3 3 3 100 +1 3 3 3 2 3 1 3 100 +1 3 3 3 2 3 2 3 100 +1 3 3 3 2 3 3 3 100 +1 4 4 4 1 4 1 4 100 +1 4 4 4 1 4 2 4 100 +1 4 4 4 1 4 3 4 100 +1 4 4 4 2 4 1 4 100 +1 4 4 4 2 4 2 4 100 +1 4 4 4 2 4 3 4 100 +1 5 5 5 1 5 1 5 100 +1 5 5 5 1 5 2 5 100 +1 5 5 5 1 5 3 5 100 +1 5 5 5 2 5 1 5 100 +1 5 5 5 2 5 2 5 100 +1 5 5 5 2 5 3 5 100 +# test opposite way, where hint enables the optimization instead of disabling it +set optimizer_switch='split_materialized=off'; +# default showing lateral derived optimization not used +explain +select * from +t21, +( +(t1 left join t2 on t2.a=t1.b) +left join t3 on t3.a=t1.b +) left join (select grp_id, count(*) +from +t22 join t10 left join t11 on t11.col1=t10.col1 +where +t22.pk=1 +group by grp_id) t on t.grp_id=t1.b +where +t21.pk=1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t21 const PRIMARY PRIMARY 4 const 1 Using index +1 PRIMARY t1 ALL NULL NULL NULL NULL 5 +1 PRIMARY t2 ref a a 5 test.t1.b 2 Using where +1 PRIMARY t3 ref a a 5 test.t1.b 3 Using where +1 PRIMARY ref key0 key0 5 test.t1.b 10 Using where +2 DERIVED t22 const PRIMARY PRIMARY 4 const 1 Using index; Using temporary; Using filesort +2 DERIVED t10 ALL NULL NULL NULL NULL 10000 +2 DERIVED t11 ALL NULL NULL NULL NULL 10 Using where; Using join buffer (flat, BNL join) +select * from +t21, +( +(t1 left join t2 on t2.a=t1.b) +left join t3 on t3.a=t1.b +) left join (select grp_id, count(*) +from +t22 join t10 left join t11 on t11.col1=t10.col1 +where +t22.pk=1 +group by grp_id) t on t.grp_id=t1.b +where +t21.pk=1; +pk a b a b a b grp_id count(*) +1 1 1 1 1 1 1 1 100 +1 1 1 1 1 1 2 1 100 +1 1 1 1 1 1 3 1 100 +1 1 1 1 2 1 1 1 100 +1 1 1 1 2 1 2 1 100 +1 1 1 1 2 1 3 1 100 +1 2 2 2 1 2 1 2 100 +1 2 2 2 1 2 2 2 100 +1 2 2 2 1 2 3 2 100 +1 2 2 2 2 2 1 2 100 +1 2 2 2 2 2 2 2 100 +1 2 2 2 2 2 3 2 100 +1 3 3 3 1 3 1 3 100 +1 3 3 3 1 3 2 3 100 +1 3 3 3 1 3 3 3 100 +1 3 3 3 2 3 1 3 100 +1 3 3 3 2 3 2 3 100 +1 3 3 3 2 3 3 3 100 +1 4 4 4 1 4 1 4 100 +1 4 4 4 1 4 2 4 100 +1 4 4 4 1 4 3 4 100 +1 4 4 4 2 4 1 4 100 +1 4 4 4 2 4 2 4 100 +1 4 4 4 2 4 3 4 100 +1 5 5 5 1 5 1 5 100 +1 5 5 5 1 5 2 5 100 +1 5 5 5 1 5 3 5 100 +1 5 5 5 2 5 1 5 100 +1 5 5 5 2 5 2 5 100 +1 5 5 5 2 5 3 5 100 +# cases where hint enables lateral derived optimization +explain +select /*+ split_materialized(t) */ * from +t21, +( +(t1 left join t2 on t2.a=t1.b) +left join t3 on t3.a=t1.b +) left join (select grp_id, count(*) +from +t22 join t10 left join t11 on t11.col1=t10.col1 +where +t22.pk=1 +group by grp_id) t on t.grp_id=t1.b +where +t21.pk=1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t21 const PRIMARY PRIMARY 4 const 1 Using index +1 PRIMARY t1 ALL NULL NULL NULL NULL 5 +1 PRIMARY t2 ref a a 5 test.t1.b 2 Using where +1 PRIMARY t3 ref a a 5 test.t1.b 3 Using where +1 PRIMARY ref key0 key0 5 test.t1.b 10 Using where +2 LATERAL DERIVED t22 const PRIMARY PRIMARY 4 const 1 Using index +2 LATERAL DERIVED t10 ref grp_id grp_id 5 test.t1.b 100 +2 LATERAL DERIVED t11 ALL NULL NULL NULL NULL 10 Using where; Using join buffer (flat, BNL join) +select /*+ split_materialized(t) */ * from +t21, +( +(t1 left join t2 on t2.a=t1.b) +left join t3 on t3.a=t1.b +) left join (select grp_id, count(*) +from +t22 join t10 left join t11 on t11.col1=t10.col1 +where +t22.pk=1 +group by grp_id) t on t.grp_id=t1.b +where +t21.pk=1; +pk a b a b a b grp_id count(*) +1 1 1 1 1 1 1 1 100 +1 1 1 1 1 1 2 1 100 +1 1 1 1 1 1 3 1 100 +1 1 1 1 2 1 1 1 100 +1 1 1 1 2 1 2 1 100 +1 1 1 1 2 1 3 1 100 +1 2 2 2 1 2 1 2 100 +1 2 2 2 1 2 2 2 100 +1 2 2 2 1 2 3 2 100 +1 2 2 2 2 2 1 2 100 +1 2 2 2 2 2 2 2 100 +1 2 2 2 2 2 3 2 100 +1 3 3 3 1 3 1 3 100 +1 3 3 3 1 3 2 3 100 +1 3 3 3 1 3 3 3 100 +1 3 3 3 2 3 1 3 100 +1 3 3 3 2 3 2 3 100 +1 3 3 3 2 3 3 3 100 +1 4 4 4 1 4 1 4 100 +1 4 4 4 1 4 2 4 100 +1 4 4 4 1 4 3 4 100 +1 4 4 4 2 4 1 4 100 +1 4 4 4 2 4 2 4 100 +1 4 4 4 2 4 3 4 100 +1 5 5 5 1 5 1 5 100 +1 5 5 5 1 5 2 5 100 +1 5 5 5 1 5 3 5 100 +1 5 5 5 2 5 1 5 100 +1 5 5 5 2 5 2 5 100 +1 5 5 5 2 5 3 5 100 +set optimizer_switch=@save_optimizer_switch; +drop table t1, t2, t3, t10, t11, t21, t22; +# +# end case 2 +# +# +# case 3 +# +set @save_optimizer_switch=@@optimizer_switch; +create table t1 (a char(1)) engine=myisam; +insert into t1 values ('1'),('2'); +create table t2 (b int, key(b)) engine=myisam; +alter table t2 disable keys; +insert into t2 values (1),(2),(3); +alter table t2 enable keys; +create table t3 (c int) engine=myisam; +insert into t3 (c) select seq from seq_1_to_101; +# default showing lateral derived optimization in use +explain +select * from t1 where t1.a in ( +select b from ( +select t2.b from t2 where not exists ( +select 1 from t3 +) group by b +) sq +); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where +1 PRIMARY eq_ref distinct_key distinct_key 5 test.t1.a 1 Using where +3 LATERAL DERIVED t2 ref b b 5 test.t1.a 1 Using where; Using index; Using temporary; Using filesort +4 SUBQUERY t3 ALL NULL NULL NULL NULL 101 +select * from t1 where t1.a in ( +select b from ( +select t2.b from t2 where not exists ( +select 1 from t3 +) group by b +) sq +); +a +# cases where hint disables lateral derived optimization +explain +select /*+ no_split_materialized(@qb1 sq) */ * from t1 where t1.a in ( +select /*+ qb_name(qb1) */ b from ( +select /*+ qb_name(qb2) */ t2.b from t2 where not exists ( +select 1 from t3 +) group by b +) sq +); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where +1 PRIMARY eq_ref distinct_key distinct_key 5 test.t1.a 1 Using where +3 DERIVED t2 range NULL b 5 NULL 3 Using where; Using index for group-by +4 SUBQUERY t3 ALL NULL NULL NULL NULL 101 +select /*+ no_split_materialized(@qb1 sq) */ * from t1 where t1.a in ( +select /*+ qb_name(qb1) */ b from ( +select /*+ qb_name(qb2) */ t2.b from t2 where not exists ( +select 1 from t3 +) group by b +) sq +); +a +# test opposite way, where hint enables the optimization instead of disabling it +set optimizer_switch='split_materialized=off'; +# default showing lateral derived optimization not used +explain +select * from t1 where t1.a in ( +select b from ( +select t2.b from t2 where not exists ( +select 1 from t3 +) group by b +) sq +); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where +1 PRIMARY eq_ref distinct_key distinct_key 5 test.t1.a 1 Using where +3 DERIVED t2 range NULL b 5 NULL 3 Using where; Using index for group-by +4 SUBQUERY t3 ALL NULL NULL NULL NULL 101 +select * from t1 where t1.a in ( +select b from ( +select t2.b from t2 where not exists ( +select 1 from t3 +) group by b +) sq +); +a +# cases where hint enables lateral derived optimization +explain select /*+ split_materialized(@qb1 sq) */ * from t1 where t1.a in ( +select /*+ qb_name(qb1) */ b from ( +select /*+ qb_name(qb2) */ t2.b from t2 where not exists ( +select 1 from t3 +) group by b +) sq +); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where +1 PRIMARY eq_ref distinct_key distinct_key 5 test.t1.a 1 Using where +3 LATERAL DERIVED t2 ref b b 5 test.t1.a 1 Using where; Using index; Using temporary; Using filesort +4 SUBQUERY t3 ALL NULL NULL NULL NULL 101 +select /*+ split_materialized(@qb1 sq) */ * from t1 where t1.a in ( +select /*+ qb_name(qb1) */ b from ( +select /*+ qb_name(qb2) */ t2.b from t2 where not exists ( +select 1 from t3 +) group by b +) sq +); +a +set optimizer_switch=@save_optimizer_switch; +drop table t1, t2, t3; +# +# end case 3 +# +# +# case 4 +# +create table one_k(a int); +insert into one_k select seq from seq_1_to_1000; +CREATE TABLE t1000 ( +grp int(11) DEFAULT NULL, +val int(11) DEFAULT NULL, +KEY grp (grp) +); +insert into t1000 select A.seq, B.seq from seq_1_to_100 A, seq_1_to_10 B; +analyze table t1000; +Table Op Msg_type Msg_text +test.t1000 analyze status Engine-independent statistics collected +test.t1000 analyze status Table is already up to date +# force lateral derived when optimizer otherwise wouldn't use it +explain +select * +from +one_k T1, (select grp, count(*) from t1000 group by grp) TBL where TBL.grp=T1.a; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY T1 ALL NULL NULL NULL NULL 1000 Using where +1 PRIMARY ref key0 key0 5 test.T1.a 10 +2 DERIVED t1000 index grp grp 5 NULL 1000 Using index; Using temporary; Using filesort +explain +select /*+ SPLIT_MATERIALIZED(TBL) */ * +from +one_k T1, (select grp, count(*) from t1000 group by grp) TBL where TBL.grp=T1.a; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY T1 ALL NULL NULL NULL NULL 1000 Using where +1 PRIMARY ref key0 key0 5 test.T1.a 1 +2 LATERAL DERIVED t1000 ref grp grp 5 test.T1.a 10 Using index +drop table one_k, t1000; +# +# end case 4 +# +# +# End 12.1 tests +# diff --git a/mysql-test/main/opt_hints_split_materialized.test b/mysql-test/main/opt_hints_split_materialized.test new file mode 100644 index 00000000000..2b5899968e7 --- /dev/null +++ b/mysql-test/main/opt_hints_split_materialized.test @@ -0,0 +1,525 @@ +--echo # +--echo # MDEV-36092 New-style hint: [NO_]SPLIT_MATERIALIZED +--echo # + +--source include/have_innodb.inc +--source include/have_sequence.inc + +set @save_optimizer_switch=@@optimizer_switch; + +--echo # +--echo # case 1 +--echo # +create table t1 ( + n1 int(10) not null, + n2 int(10) not null, + c1 char(1) not null, + key c1 (c1), + key n1_c1_n2 (n1,c1,n2) +) engine=innodb charset=latin1; +insert into t1 values (0, 2, 'a'), (1, 3, 'a'); +insert into t1 select seq+1,seq+2,'c' from seq_1_to_1000; + +analyze table t1; + +--echo # default showing lateral derived optimization in use +explain +select t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1; + +select t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1; + +--echo # cases where hint disables lateral derived optimization +explain +select /*+ no_split_materialized(t) */ t1.n1 from t1, + (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1; + +select /*+ no_split_materialized(t) */ t1.n1 from t1, + (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1; + +--echo # query having two subqueries, both of which are subject to LATERAL DERIVED optimization +--echo # explain and result without hints +explain +with cte as ( +select t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select * from cte; + +with cte as ( +select /*+ QB_NAME(qb1) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select /*+ QB_NAME(qb2) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select * from cte; + +--echo # explain and result with first half of query disabling the optimization +explain +with cte as ( +select /*+ QB_NAME(qb1) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select /*+ QB_NAME(qb2) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select /*+ NO_SPLIT_MATERIALIZED(t@qb1) */ * from cte; + +with cte as ( +select /*+ QB_NAME(qb1) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select /*+ QB_NAME(qb2) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select /*+ NO_SPLIT_MATERIALIZED(t@qb1) */ * from cte; + +--echo # explain and result with second half of query disabling the optimization +explain +with cte as ( +select /*+ QB_NAME(qb1) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select /*+ QB_NAME(qb2) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select /*+ NO_SPLIT_MATERIALIZED(t@qb2) */ * from cte; + +with cte as ( +select /*+ QB_NAME(qb1) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select /*+ QB_NAME(qb2) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select /*+ NO_SPLIT_MATERIALIZED(t@qb2) */ * from cte; + +--echo # explain and result with both halves of query disabling the optimization +explain +with cte as ( +select /*+ QB_NAME(qb1) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select /*+ QB_NAME(qb2) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select /*+ NO_SPLIT_MATERIALIZED(t@qb1) NO_SPLIT_MATERIALIZED(t@qb2) */ * from cte; + +with cte as ( +select /*+ QB_NAME(qb1) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select /*+ QB_NAME(qb2) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select /*+ NO_SPLIT_MATERIALIZED(t@qb1) NO_SPLIT_MATERIALIZED(t@qb2) */ * from cte; + +--echo # test opposite way, where hint enables the optimization instead of disabling it +set optimizer_switch='split_materialized=off'; + +--echo # default showing lateral derived optimization not used +explain +select t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1; + +select t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1; + +--echo # cases where hint enables lateral derived optimization +explain +select /*+ split_materialized(t) */ t1.n1 from t1, + (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1; + +select /*+ split_materialized(t) */ t1.n1 from t1, + (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1; + +--echo # query having two subqueries, both of which are subject to LATERAL DERIVED optimization +--echo # explain and result without hints +explain +with cte as ( +select t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select * from cte; + +with cte as ( +select t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select * from cte; + +--echo # explain and result with first half of query enabling the optimization +explain +with cte as ( +select /*+ QB_NAME(qb1) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select /*+ QB_NAME(qb2) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select /*+ SPLIT_MATERIALIZED(t@qb1) */ * from cte; + +with cte as ( +select /*+ QB_NAME(qb1) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select /*+ QB_NAME(qb2) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select /*+ SPLIT_MATERIALIZED(t@qb1) */ * from cte; + +--echo # explain and result with second half of query enabling the optimization +explain +with cte as ( +select /*+ QB_NAME(qb1) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select /*+ QB_NAME(qb2) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select /*+ SPLIT_MATERIALIZED(t@qb2) */ * from cte; + +with cte as ( +select /*+ QB_NAME(qb1) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select /*+ QB_NAME(qb2) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select /*+ SPLIT_MATERIALIZED(t@qb2) */ * from cte; + +--echo # explain and result with both halves of query enabling the optimization +explain +with cte as ( +select /*+ QB_NAME(qb1) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select /*+ QB_NAME(qb2) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select /*+ SPLIT_MATERIALIZED(t@qb1) SPLIT_MATERIALIZED(t@qb2) */ * from cte; + +with cte as ( +select /*+ QB_NAME(qb1) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1 +union +select /*+ QB_NAME(qb2) */ t1.n1 from t1, (select n1, n2 from t1 where c1 = 'a' group by n1) as t + where t.n1 = t1.n1 and t.n2 = t1.n2 and c1 = 'a' group by n1) +select /*+ SPLIT_MATERIALIZED(t@qb1) SPLIT_MATERIALIZED(t@qb2) */ * from cte; + +set optimizer_switch=@save_optimizer_switch; +drop table t1; +--echo # +--echo # end case 1 +--echo # + +--echo # +--echo # case 2 +--echo # +# 5 values +set @save_optimizer_switch=@@optimizer_switch; + +create table t1(a int, b int); +insert into t1 select seq,seq from seq_1_to_5; + +# 5 value groups of size 2 each +create table t2(a int, b int, key(a)); +insert into t2 +select a.seq,b.seq from seq_1_to_25 a, seq_1_to_2 b; + +# 5 value groups of size 3 each +create table t3(a int, b int, key(a)); +insert into t3 +select a.seq,b.seq from seq_1_to_5 a, seq_1_to_3 b; + +analyze table t1,t2,t3 persistent for all; + +create table t10 ( + grp_id int, + col1 int, + key(grp_id) +); + +# 100 groups of 100 values each +insert into t10 +select + a.seq, + b.seq +from + seq_1_to_100 a, + seq_1_to_100 b; + +# and x10 multiplier + +create table t11 ( + col1 int, + col2 int +); +insert into t11 +select a.seq, a.seq from seq_1_to_10 a; + +analyze table t10,t11 persistent for all; + +create table t21 (pk int primary key); +insert into t21 values (1),(2),(3); + +create table t22 (pk int primary key); +insert into t22 values (1),(2),(3); + +--echo # default showing lateral derived optimization in use +explain +select * from + t21, + ( + (t1 left join t2 on t2.a=t1.b) + left join t3 on t3.a=t1.b + ) left join (select grp_id, count(*) + from + t22 join t10 left join t11 on t11.col1=t10.col1 + where + t22.pk=1 + group by grp_id) t on t.grp_id=t1.b +where + t21.pk=1; + +select * from + t21, + ( + (t1 left join t2 on t2.a=t1.b) + left join t3 on t3.a=t1.b + ) left join (select grp_id, count(*) + from + t22 join t10 left join t11 on t11.col1=t10.col1 + where + t22.pk=1 + group by grp_id) t on t.grp_id=t1.b +where + t21.pk=1; + +--echo # cases where hint disables lateral derived optimization +explain +select /*+ no_split_materialized(t) */ * from + t21, + ( + (t1 left join t2 on t2.a=t1.b) + left join t3 on t3.a=t1.b + ) left join (select grp_id, count(*) + from + t22 join t10 left join t11 on t11.col1=t10.col1 + where + t22.pk=1 + group by grp_id) t on t.grp_id=t1.b +where + t21.pk=1; + +select /*+ no_split_materialized(t) */ * from + t21, + ( + (t1 left join t2 on t2.a=t1.b) + left join t3 on t3.a=t1.b + ) left join (select grp_id, count(*) + from + t22 join t10 left join t11 on t11.col1=t10.col1 + where + t22.pk=1 + group by grp_id) t on t.grp_id=t1.b +where + t21.pk=1; + +--echo # test opposite way, where hint enables the optimization instead of disabling it +set optimizer_switch='split_materialized=off'; + +--echo # default showing lateral derived optimization not used +explain +select * from + t21, + ( + (t1 left join t2 on t2.a=t1.b) + left join t3 on t3.a=t1.b + ) left join (select grp_id, count(*) + from + t22 join t10 left join t11 on t11.col1=t10.col1 + where + t22.pk=1 + group by grp_id) t on t.grp_id=t1.b +where + t21.pk=1; + +select * from + t21, + ( + (t1 left join t2 on t2.a=t1.b) + left join t3 on t3.a=t1.b + ) left join (select grp_id, count(*) + from + t22 join t10 left join t11 on t11.col1=t10.col1 + where + t22.pk=1 + group by grp_id) t on t.grp_id=t1.b +where + t21.pk=1; + +--echo # cases where hint enables lateral derived optimization +explain +select /*+ split_materialized(t) */ * from + t21, + ( + (t1 left join t2 on t2.a=t1.b) + left join t3 on t3.a=t1.b + ) left join (select grp_id, count(*) + from + t22 join t10 left join t11 on t11.col1=t10.col1 + where + t22.pk=1 + group by grp_id) t on t.grp_id=t1.b +where + t21.pk=1; + +select /*+ split_materialized(t) */ * from + t21, + ( + (t1 left join t2 on t2.a=t1.b) + left join t3 on t3.a=t1.b + ) left join (select grp_id, count(*) + from + t22 join t10 left join t11 on t11.col1=t10.col1 + where + t22.pk=1 + group by grp_id) t on t.grp_id=t1.b +where + t21.pk=1; + +set optimizer_switch=@save_optimizer_switch; +drop table t1, t2, t3, t10, t11, t21, t22; +--echo # +--echo # end case 2 +--echo # + +--echo # +--echo # case 3 +--echo # +set @save_optimizer_switch=@@optimizer_switch; + +create table t1 (a char(1)) engine=myisam; +insert into t1 values ('1'),('2'); +create table t2 (b int, key(b)) engine=myisam; +alter table t2 disable keys; +insert into t2 values (1),(2),(3); +alter table t2 enable keys; +create table t3 (c int) engine=myisam; +insert into t3 (c) select seq from seq_1_to_101; + +--echo # default showing lateral derived optimization in use +explain +select * from t1 where t1.a in ( + select b from ( + select t2.b from t2 where not exists ( + select 1 from t3 + ) group by b + ) sq +); + +select * from t1 where t1.a in ( + select b from ( + select t2.b from t2 where not exists ( + select 1 from t3 + ) group by b + ) sq +); + +--echo # cases where hint disables lateral derived optimization +explain +select /*+ no_split_materialized(@qb1 sq) */ * from t1 where t1.a in ( + select /*+ qb_name(qb1) */ b from ( + select /*+ qb_name(qb2) */ t2.b from t2 where not exists ( + select 1 from t3 + ) group by b + ) sq +); + +select /*+ no_split_materialized(@qb1 sq) */ * from t1 where t1.a in ( + select /*+ qb_name(qb1) */ b from ( + select /*+ qb_name(qb2) */ t2.b from t2 where not exists ( + select 1 from t3 + ) group by b + ) sq +); + +--echo # test opposite way, where hint enables the optimization instead of disabling it +set optimizer_switch='split_materialized=off'; + +--echo # default showing lateral derived optimization not used +explain +select * from t1 where t1.a in ( + select b from ( + select t2.b from t2 where not exists ( + select 1 from t3 + ) group by b + ) sq +); + +select * from t1 where t1.a in ( + select b from ( + select t2.b from t2 where not exists ( + select 1 from t3 + ) group by b + ) sq +); + +--echo # cases where hint enables lateral derived optimization +explain select /*+ split_materialized(@qb1 sq) */ * from t1 where t1.a in ( + select /*+ qb_name(qb1) */ b from ( + select /*+ qb_name(qb2) */ t2.b from t2 where not exists ( + select 1 from t3 + ) group by b + ) sq +); + +select /*+ split_materialized(@qb1 sq) */ * from t1 where t1.a in ( + select /*+ qb_name(qb1) */ b from ( + select /*+ qb_name(qb2) */ t2.b from t2 where not exists ( + select 1 from t3 + ) group by b + ) sq +); + +set optimizer_switch=@save_optimizer_switch; +drop table t1, t2, t3; +--echo # +--echo # end case 3 +--echo # + +--echo # +--echo # case 4 +--echo # +create table one_k(a int); +insert into one_k select seq from seq_1_to_1000; + +CREATE TABLE t1000 ( + grp int(11) DEFAULT NULL, + val int(11) DEFAULT NULL, + KEY grp (grp) +); + +insert into t1000 select A.seq, B.seq from seq_1_to_100 A, seq_1_to_10 B; +analyze table t1000; + +--echo # force lateral derived when optimizer otherwise wouldn't use it +explain +select * +from + one_k T1, (select grp, count(*) from t1000 group by grp) TBL where TBL.grp=T1.a; + +explain +select /*+ SPLIT_MATERIALIZED(TBL) */ * +from + one_k T1, (select grp, count(*) from t1000 group by grp) TBL where TBL.grp=T1.a; + +drop table one_k, t1000; +--echo # +--echo # end case 4 +--echo # + +--echo # +--echo # End 12.1 tests +--echo # diff --git a/sql/opt_hints.cc b/sql/opt_hints.cc index 4189385ec2d..357bce72203 100644 --- a/sql/opt_hints.cc +++ b/sql/opt_hints.cc @@ -47,6 +47,7 @@ struct st_opt_hint_info opt_hint_info[]= {{STRING_WITH_LEN("JOIN_FIXED_ORDER")}, false, true, false}, {{STRING_WITH_LEN("DERIVED_CONDITION_PUSHDOWN")}, false, false, false}, {{STRING_WITH_LEN("MERGE")}, false, false, false}, + {{STRING_WITH_LEN("SPLIT_MATERIALIZED")}, false, false, false}, {null_clex_str, 0, 0, 0} }; @@ -608,6 +609,54 @@ static bool get_hint_state(Opt_hints *hint, } +/* + In addition to indicating the state of a hint, also indicates + if the hint is present or not. Serves to disambiguate cases + that the other version of hint_table_state cannot, such as + when a hint is forcing a behavior in the optimizer that it + would not normally do and the corresponding optimizer switch + is enabled. + + @param thd Current thread connection state + @param table_list Table having the hint + @param type_arg The hint kind in question + + @return appropriate value from hint_state enumeration + indicating hint enabled/disabled (if present) or + if the hint was not present. + */ + +hint_state hint_table_state(const THD *thd, + const TABLE_LIST *table_list, + opt_hints_enum type_arg) +{ + if (!table_list->opt_hints_qb) + return hint_state::NOT_PRESENT; + + DBUG_ASSERT(!opt_hint_info[type_arg].has_arguments); + + Opt_hints *hint= table_list->opt_hints_table; + Opt_hints *parent_hint= table_list->opt_hints_qb; + + if (hint && hint->is_specified(type_arg)) + { + const bool hint_value= hint->get_switch(type_arg); + return hint_value ? hint_state::ENABLED : + hint_state::DISABLED; + } + + if (opt_hint_info[type_arg].check_upper_lvl && + parent_hint->is_specified(type_arg)) + { + const bool hint_value= parent_hint->get_switch(type_arg); + return hint_value ? hint_state::ENABLED : + hint_state::DISABLED; + } + + return hint_state::NOT_PRESENT; +} + + /* @brief Check whether a given optimization is enabled for table.keyno. diff --git a/sql/opt_hints.h b/sql/opt_hints.h index 642846e0d78..ec6860d3795 100644 --- a/sql/opt_hints.h +++ b/sql/opt_hints.h @@ -659,6 +659,14 @@ public: }; +enum class hint_state +{ + NOT_PRESENT, // Hint is not specified + ENABLED, // Hint is specified as enabled + DISABLED // Hint is specified as disabled +}; + + /** Returns key hint value if hint is specified, returns optimizer switch value if hint is not specified. @@ -706,6 +714,14 @@ bool hint_table_state(const THD *thd, const TABLE_LIST *table_list, bool hint_table_state(const THD *thd, const TABLE *table, opt_hints_enum type_arg, bool fallback_value); + +/* + Similar to above but returns hint_state enum +*/ +hint_state hint_table_state(const THD *thd, + const TABLE_LIST *table_list, + opt_hints_enum type_arg); + #ifndef DBUG_OFF const char *dbug_print_hints(Opt_hints_qb *hint); #endif diff --git a/sql/opt_hints_parser.cc b/sql/opt_hints_parser.cc index 0ff5bf20ad2..4dcee925a9b 100644 --- a/sql/opt_hints_parser.cc +++ b/sql/opt_hints_parser.cc @@ -134,11 +134,15 @@ Optimizer_hint_tokenizer::find_keyword(const LEX_CSTRING &str) case 18: if ("MAX_EXECUTION_TIME"_Lex_ident_column.streq(str)) return TokenID::keyword_MAX_EXECUTION_TIME; + if ("SPLIT_MATERIALIZED"_Lex_ident_column.streq(str)) + return TokenID::keyword_SPLIT_MATERIALIZED; break; case 21: if ("NO_RANGE_OPTIMIZATION"_Lex_ident_column.streq(str)) return TokenID::keyword_NO_RANGE_OPTIMIZATION; + if ("NO_SPLIT_MATERIALIZED"_Lex_ident_column.streq(str)) + return TokenID::keyword_NO_SPLIT_MATERIALIZED; break; case 26: @@ -342,21 +346,29 @@ bool Parser::Table_level_hint::resolve(Parse_context *pc) const hint_state= false; break; case TokenID::keyword_DERIVED_CONDITION_PUSHDOWN: - hint_type= DERIVED_CONDITION_PUSHDOWN_HINT_ENUM; - hint_state= true; - break; + hint_type= DERIVED_CONDITION_PUSHDOWN_HINT_ENUM; + hint_state= true; + break; case TokenID::keyword_NO_DERIVED_CONDITION_PUSHDOWN: - hint_type= DERIVED_CONDITION_PUSHDOWN_HINT_ENUM; - hint_state= false; - break; + hint_type= DERIVED_CONDITION_PUSHDOWN_HINT_ENUM; + hint_state= false; + break; case TokenID::keyword_MERGE: - hint_type= MERGE_HINT_ENUM; - hint_state= true; - break; + hint_type= MERGE_HINT_ENUM; + hint_state= true; + break; case TokenID::keyword_NO_MERGE: - hint_type= MERGE_HINT_ENUM; - hint_state= false; - break; + hint_type= MERGE_HINT_ENUM; + hint_state= false; + break; + case TokenID::keyword_SPLIT_MATERIALIZED: + hint_type= SPLIT_MATERIALIZED_HINT_ENUM; + hint_state= true; + break; + case TokenID::keyword_NO_SPLIT_MATERIALIZED: + hint_type= SPLIT_MATERIALIZED_HINT_ENUM; + hint_state= false; + break; default: DBUG_ASSERT(0); return true; diff --git a/sql/opt_hints_parser.h b/sql/opt_hints_parser.h index 7cf22c45a38..c63cd3f94ea 100644 --- a/sql/opt_hints_parser.h +++ b/sql/opt_hints_parser.h @@ -50,6 +50,7 @@ enum opt_hints_enum JOIN_FIXED_ORDER_HINT_ENUM, DERIVED_CONDITION_PUSHDOWN_HINT_ENUM, MERGE_HINT_ENUM, + SPLIT_MATERIALIZED_HINT_ENUM, MAX_HINT_ENUM // This one must be the last in the list }; @@ -118,7 +119,9 @@ public: keyword_DERIVED_CONDITION_PUSHDOWN, keyword_NO_DERIVED_CONDITION_PUSHDOWN, keyword_MERGE, - keyword_NO_MERGE + keyword_NO_MERGE, + keyword_SPLIT_MATERIALIZED, + keyword_NO_SPLIT_MATERIALIZED }; class Token: public Lex_cstring @@ -373,7 +376,9 @@ private: id == TokenID::keyword_DERIVED_CONDITION_PUSHDOWN || id == TokenID::keyword_NO_DERIVED_CONDITION_PUSHDOWN || id == TokenID::keyword_MERGE || - id == TokenID::keyword_NO_MERGE; + id == TokenID::keyword_NO_MERGE || + id == TokenID::keyword_SPLIT_MATERIALIZED || + id == TokenID::keyword_NO_SPLIT_MATERIALIZED; } }; class Table_level_hint_type: public TokenChoicejoin->spl_opt_info= spl_info; + DBUG_ASSERT(spl_info); + spl_info->join->spl_opt_info= spl_info; spl_opt_info= spl_info; } @@ -320,6 +323,40 @@ double TABLE::get_materialization_cost() } +/** + Returns true if split materialization is permitted for the + derived table passed in argument 'derived'. + + @param thd The connection state for the current thread. + @param derived The candidate derived table for split materialization. + @param hint [OUT] One of the values from the hint_state enumeration + found in opt_hints.h + @return true if split materialization allowed, either by hint + or by optimizer option. The hint takes precedence. + */ + +static bool is_split_materialized_allowed(THD *thd, + const TABLE_LIST *derived, + hint_state *hint) +{ + if (!derived) + { + *hint= hint_state::DISABLED; // there is no derived table to hint on + return false; + } + + *hint= hint_table_state(thd, + derived, + SPLIT_MATERIALIZED_HINT_ENUM); + + const bool opt_flag= optimizer_flag(thd, OPTIMIZER_SWITCH_SPLIT_MATERIALIZED); + const bool allow_split= (*hint == hint_state::ENABLED || + (*hint == hint_state::NOT_PRESENT && opt_flag)); + + return allow_split; +} + + /* This structure is auxiliary and used only in the function that follows it */ struct SplM_field_ext_info: public SplM_field_info { @@ -330,7 +367,8 @@ struct SplM_field_ext_info: public SplM_field_info /** @brief - Check whether this join is one for potentially splittable materialized table + Check whether this join is one for potentially splittable materialized + table @details The function checks whether this join is for select that specifies @@ -339,7 +377,8 @@ struct SplM_field_ext_info: public SplM_field_info of the TABLE structure for T. The function returns a positive answer if the following holds: - 1. the optimizer switch 'split_materialized' is set 'on' + 1. The is_split_materialized_allowed() function indicates that split + materialization is permitted for the derived table. 2. the select owning this join specifies a materialized derived/view/cte T 3. this is the only select in the specification of T 4. condition pushdown is not prohibited into T @@ -355,7 +394,7 @@ struct SplM_field_ext_info: public SplM_field_info 9. There are defined some keys usable for ref access of fields from C with available statistics. 10. The select doesn't use WITH ROLLUP (This limitation can probably be - lifted) + lifted) @retval true if the answer is positive @@ -367,8 +406,10 @@ bool JOIN::check_for_splittable_materialized() ORDER *partition_list= 0; st_select_lex_unit *unit= select_lex->master_unit(); TABLE_LIST *derived= unit->derived; - if (!(optimizer_flag(thd, OPTIMIZER_SWITCH_SPLIT_MATERIALIZED)) || // !(1) - !(derived && derived->is_materialized_derived()) || // !(2) + + hint_state hint; + if (!is_split_materialized_allowed(thd, derived, &hint) || // !(1) + !derived->is_materialized_derived() || // !(2) (unit->first_select()->next_select()) || // !(3) (derived->prohibit_cond_pushdown) || // !(4) (derived->is_recursive_with_table()) || // !(5) @@ -519,6 +560,7 @@ bool JOIN::check_for_splittable_materialized() spl_opt_info->tables_usable_for_splitting= 0; spl_opt_info->spl_field_cnt= spl_field_cnt; spl_opt_info->spl_fields= spl_field; + spl_opt_info->hint_forced_split= (hint == hint_state::ENABLED); { Json_writer_array trace_range(thd, "split_candidates"); @@ -1130,8 +1172,8 @@ SplM_plan_info * JOIN_TAB::choose_best_splitting(uint idx, spl_plan->cost= (join->best_positions[join->table_count-1].read_time + oper_cost); - chosen= (refills * spl_plan->cost + COST_EPS < - spl_opt_info->unsplit_cost); + chosen= ((refills * spl_plan->cost + COST_EPS < + spl_opt_info->unsplit_cost) || spl_opt_info->hint_forced_split); if (unlikely(thd->trace_started())) { @@ -1149,6 +1191,9 @@ SplM_plan_info * JOIN_TAB::choose_best_splitting(uint idx, add("refills", refills). add("total_splitting_cost", refills * spl_plan->cost). add("chosen", chosen); + + if (spl_opt_info->hint_forced_split) + find_trace.add("forced_by_hint", true); } memcpy((char *) spl_plan->best_positions, (char *) join->best_positions, @@ -1160,8 +1205,11 @@ SplM_plan_info * JOIN_TAB::choose_best_splitting(uint idx, else { trace_obj.add("cached_plan_found", 1); - chosen= (refills * spl_plan->cost + COST_EPS < - spl_opt_info->unsplit_cost); + if (spl_opt_info->hint_forced_split) + trace_obj.add("forced_by_hint", true); + + chosen= ((refills * spl_plan->cost + COST_EPS < + spl_opt_info->unsplit_cost) || spl_opt_info->hint_forced_split); already_printed= 0; } } diff --git a/sql/table.h b/sql/table.h index 43267ac2fa3..e61c9ead0b0 100644 --- a/sql/table.h +++ b/sql/table.h @@ -2971,6 +2971,11 @@ struct TABLE_LIST /* I_S: Flags to open_table (e.g. OPEN_TABLE_ONLY or OPEN_VIEW_ONLY) */ uint i_s_requested_object; + /* + The [NO_]SPLIT_MATERIALIZED hint will not override this because + this is in place for correctness (see Item_func_set_user_var::fix_fields + for the rationale). + */ bool prohibit_cond_pushdown; /*