summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Babaev <igor@askmonty.org>2017-12-30 12:29:09 -0800
committerIgor Babaev <igor@askmonty.org>2017-12-30 12:29:09 -0800
commit4f0299f8b3cf19c103138ff656a37c1f672e9de6 (patch)
treeda7c706aed70d0bc25cecdcd1e9715abc9bb69e0
parent7a66e0ab8f52f3bd32850463daa05f9a2401e6b1 (diff)
downloadmariadb-git-4f0299f8b3cf19c103138ff656a37c1f672e9de6.tar.gz
This is a full cost-based implementation of the optimization that employs
splitting technique for equi-joins of materialized derived tables/views/CTEs. (see mdev-13369 and mdev-13389).
-rw-r--r--libmysqld/CMakeLists.txt1
-rw-r--r--mysql-test/r/derived_cond_pushdown.result1326
-rw-r--r--mysql-test/r/mysqld--help.result4
-rw-r--r--mysql-test/r/selectivity.result4
-rw-r--r--mysql-test/r/selectivity_innodb.result4
-rw-r--r--mysql-test/suite/sys_vars/r/optimizer_switch_basic.result36
-rw-r--r--mysql-test/suite/sys_vars/r/sysvars_server_embedded.result9
-rw-r--r--mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result8
-rw-r--r--mysql-test/t/derived_cond_pushdown.test161
-rw-r--r--sql/CMakeLists.txt1
-rw-r--r--sql/opt_split.cc1132
-rw-r--r--sql/opt_subselect.cc8
-rw-r--r--sql/sql_class.h2
-rw-r--r--sql/sql_const.h1
-rw-r--r--sql/sql_priv.h4
-rw-r--r--sql/sql_select.cc298
-rw-r--r--sql/sql_select.h80
-rw-r--r--sql/sys_vars.cc2
-rw-r--r--sql/table.h14
-rw-r--r--storage/tokudb/mysql-test/tokudb/r/ext_key_1_innodb.result2
-rw-r--r--storage/tokudb/mysql-test/tokudb/r/ext_key_1_tokudb.result2
-rw-r--r--storage/tokudb/mysql-test/tokudb/r/ext_key_2_innodb.result2
-rw-r--r--storage/tokudb/mysql-test/tokudb/r/ext_key_2_tokudb.result2
23 files changed, 2507 insertions, 596 deletions
diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt
index 19962df0bec..6e717267548 100644
--- a/libmysqld/CMakeLists.txt
+++ b/libmysqld/CMakeLists.txt
@@ -119,6 +119,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc
../sql/session_tracker.cc
../sql/proxy_protocol.cc
../sql/sql_tvc.cc ../sql/sql_tvc.h
+ ../sql/opt_split.cc
${GEN_SOURCES}
${MYSYS_LIBWRAP_SOURCE}
)
diff --git a/mysql-test/r/derived_cond_pushdown.result b/mysql-test/r/derived_cond_pushdown.result
index 41c8c51a09b..cc6cc190dea 100644
--- a/mysql-test/r/derived_cond_pushdown.result
+++ b/mysql-test/r/derived_cond_pushdown.result
@@ -12543,7 +12543,7 @@ drop table t1;
# MDEV-10855: Pushdown into derived with window functions
#
set @save_optimizer_switch= @@optimizer_switch;
-set optimizer_switch='split_grouping_derived=off';
+set optimizer_switch='split_materialized=off';
create table t1 (a int, c varchar(16));
insert into t1 values
(8,'aa'), (5,'cc'), (1,'bb'), (2,'aa'), (9,'cc'),
@@ -13244,59 +13244,76 @@ set optimizer_switch= @save_optimizer_switch;
# MDEV-13389: Optimization for equi-joins of derived tables with WF
# (Splitting derived tables / views with window functions)
#
-create table t1 (a int);
+create table t1 (a int, b int, index idx_b(b)) engine=myisam;
insert into t1 values
-(8), (5), (1), (2), (9), (7), (2), (7);
-create table t2 (a int, b int, index idx(a));
+(8,3), (5,7), (1,2), (2,1), (9,7), (7,5), (2,2), (7,3),
+(9,3), (8,1), (4,5), (2,3);
+create table t2 (a int, b int, c char(127), index idx_a(a)) engine=myisam;
insert into t2 values
-(7,10), (1,20), (2,23), (7,18), (1,30),
-(4,71), (3,15), (7,82), (8,12), (4,15),
-(11,33), (10,42), (4,53), (10,17), (2,90);
-set statement optimizer_switch='split_grouping_derived=off' for select t1.a,t.max,t.min
+(7,10,'x'), (1,20,'a'), (2,23,'b'), (7,18,'z'), (1,30,'c'),
+(4,71,'d'), (3,15,'x'), (7,82,'y'), (8,12,'t'), (4,15,'b'),
+(11,33,'a'), (10,42,'u'), (4,53,'p'), (10,17,'r'), (2,90,'x'),
+(17,10,'s'), (11,20,'v'), (12,23,'y'), (17,18,'a'), (11,30,'d'),
+(24,71,'h'), (23,15,'i'), (27,82,'k'), (28,12,'p'), (24,15,'q'),
+(31,33,'f'), (30,42,'h'), (40,53,'m'), (30,17,'o'), (21,90,'b'),
+(37,10,'e'), (31,20,'g'), (32,23,'f'), (37,18,'n'), (41,30,'l'),
+(54,71,'j'), (53,15,'w'), (57,82,'z'), (58,12,'k'), (54,15,'p'),
+(61,33,'c'), (60,42,'a'), (62,53,'x'), (67,17,'g'), (64,90,'v');
+insert into t2 select a+10, b+10, concat(c,'f') from t2;
+analyze table t1,t2;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+test.t2 analyze status OK
+set statement optimizer_switch='split_materialized=off' for select t1.a,t.s,t.m
from t1 join
-(select a, max(t2.b) max, min(t2.b) min from t2 group by t2.a) t
-on t1.a=t.a;
-a max min
-8 12 12
-1 30 20
-2 90 23
-7 82 10
-2 90 23
-7 82 10
-select t1.a,t.max,t.min
+(select a, sum(t2.b) as s, min(t2.c) as m from t2 group by t2.a) t
+on t1.a=t.a
+where t1.b < 3;
+a s m
+2 113 b
+8 12 t
+1 50 a
+2 113 b
+select t1.a,t.s,t.m
from t1 join
-(select a, max(t2.b) max, min(t2.b) min from t2 group by t2.a) t
-on t1.a=t.a;
-a max min
-8 12 12
-1 30 20
-2 90 23
-7 82 10
-2 90 23
-7 82 10
-explain extended select t1.a,t.max,t.min
+(select a, sum(t2.b) as s, min(t2.c) as m from t2 group by t2.a) t
+on t1.a=t.a
+where t1.b < 3;
+a s m
+2 113 b
+8 12 t
+1 50 a
+2 113 b
+explain extended select t1.a,t.s,t.m
from t1 join
-(select a, max(t2.b) max, min(t2.b) min from t2 group by t2.a) t
-on t1.a=t.a;
+(select a, sum(t2.b) as s, min(t2.c) as m from t2 group by t2.a) t
+on t1.a=t.a
+where t1.b < 3;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY t1 ALL NULL NULL NULL NULL 8 100.00 Using where
+1 PRIMARY t1 range idx_b idx_b 5 NULL 4 100.00 Using index condition; Using where
1 PRIMARY <derived2> ref key0 key0 5 test.t1.a 2 100.00
-2 LATERAL DERIVED t2 ref idx idx 5 test.t1.a 2 100.00
+2 LATERAL DERIVED t2 ref idx_a idx_a 5 test.t1.a 2 100.00
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`t`.`max` AS `max`,`t`.`min` AS `min` from `test`.`t1` join (/* select#2 */ select `test`.`t2`.`a` AS `a`,max(`test`.`t2`.`b`) AS `max`,min(`test`.`t2`.`b`) AS `min` from `test`.`t2` where `test`.`t2`.`a` = `test`.`t1`.`a` group by `test`.`t2`.`a`) `t` where `t`.`a` = `test`.`t1`.`a`
-explain format=json select t1.a,t.max,t.min
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`t`.`s` AS `s`,`t`.`m` AS `m` from `test`.`t1` join (/* select#2 */ select `test`.`t2`.`a` AS `a`,sum(`test`.`t2`.`b`) AS `s`,min(`test`.`t2`.`c`) AS `m` from `test`.`t2` where `test`.`t2`.`a` = `test`.`t1`.`a` group by `test`.`t2`.`a`) `t` where `t`.`a` = `test`.`t1`.`a` and `test`.`t1`.`b` < 3
+explain format=json select t1.a,t.s,t.m
from t1 join
-(select a, max(t2.b) max, min(t2.b) min from t2 group by t2.a) t
-on t1.a=t.a;
+(select a, sum(t2.b) as s, min(t2.c) as m from t2 group by t2.a) t
+on t1.a=t.a
+where t1.b < 3;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t1",
- "access_type": "ALL",
- "rows": 8,
+ "access_type": "range",
+ "possible_keys": ["idx_b"],
+ "key": "idx_b",
+ "key_length": "5",
+ "used_key_parts": ["b"],
+ "rows": 4,
"filtered": 100,
+ "index_condition": "t1.b < 3",
"attached_condition": "t1.a is not null"
},
"table": {
@@ -13316,8 +13333,8 @@ EXPLAIN
"table": {
"table_name": "t2",
"access_type": "ref",
- "possible_keys": ["idx"],
- "key": "idx",
+ "possible_keys": ["idx_a"],
+ "key": "idx_a",
"key_length": "5",
"used_key_parts": ["a"],
"ref": ["test.t1.a"],
@@ -13329,40 +13346,167 @@ EXPLAIN
}
}
}
-set statement optimizer_switch='split_grouping_derived=off' for select t1.a,t.max,t.min
+prepare stmt from "select t1.a,t.s,t.m
+from t1 join
+(select a, sum(t2.b) as s, min(t2.c) as m from t2 group by t2.a) t
+on t1.a=t.a
+where t1.b < 3";
+execute stmt;
+a s m
+2 113 b
+8 12 t
+1 50 a
+2 113 b
+execute stmt;
+a s m
+2 113 b
+8 12 t
+1 50 a
+2 113 b
+deallocate prepare stmt;
+set statement optimizer_switch='split_materialized=off' for select t1.a,t.s,t.m
+from t1 join
+(select a, sum(t2.b) as s, min(t2.b) as m from t2 group by t2.a) t
+on t1.a=t.a
+where t1.b <= 5;
+a s m
+8 12 12
+1 50 20
+2 113 23
+7 110 10
+2 113 23
+7 110 10
+8 12 12
+4 139 15
+2 113 23
+select t1.a,t.s,t.m
+from t1 join
+(select a, sum(t2.b) as s, min(t2.b) as m from t2 group by t2.a) t
+on t1.a=t.a
+where t1.b <= 5;
+a s m
+8 12 12
+1 50 20
+2 113 23
+7 110 10
+2 113 23
+7 110 10
+8 12 12
+4 139 15
+2 113 23
+explain extended select t1.a,t.s,t.m
+from t1 join
+(select a, sum(t2.b) as s, min(t2.b) as m from t2 group by t2.a) t
+on t1.a=t.a
+where t1.b <= 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL idx_b NULL NULL NULL 12 75.00 Using where
+1 PRIMARY <derived2> ref key0 key0 5 test.t1.a 9 100.00
+2 DERIVED t2 ALL idx_a NULL NULL NULL 90 100.00 Using temporary; Using filesort
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`t`.`s` AS `s`,`t`.`m` AS `m` from `test`.`t1` join (/* select#2 */ select `test`.`t2`.`a` AS `a`,sum(`test`.`t2`.`b`) AS `s`,min(`test`.`t2`.`b`) AS `m` from `test`.`t2` group by `test`.`t2`.`a`) `t` where `t`.`a` = `test`.`t1`.`a` and `test`.`t1`.`b` <= 5
+explain format=json select t1.a,t.s,t.m
+from t1 join
+(select a, sum(t2.b) as s, min(t2.b) as m from t2 group by t2.a) t
+on t1.a=t.a
+where t1.b <= 5;
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "possible_keys": ["idx_b"],
+ "rows": 12,
+ "filtered": 75,
+ "attached_condition": "t1.b <= 5 and t1.a is not null"
+ },
+ "table": {
+ "table_name": "<derived2>",
+ "access_type": "ref",
+ "possible_keys": ["key0"],
+ "key": "key0",
+ "key_length": "5",
+ "used_key_parts": ["a"],
+ "ref": ["test.t1.a"],
+ "rows": 9,
+ "filtered": 100,
+ "materialized": {
+ "query_block": {
+ "select_id": 2,
+ "filesort": {
+ "sort_key": "t2.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "possible_keys": ["idx_a"],
+ "rows": 90,
+ "filtered": 100
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+prepare stmt from "select t1.a,t.s,t.m
+from t1 join
+(select a, sum(t2.b) as s, min(t2.b) as m from t2 group by t2.a) t
+on t1.a=t.a
+where t1.b <= 5";
+execute stmt;
+a s m
+8 12 12
+1 50 20
+2 113 23
+7 110 10
+2 113 23
+7 110 10
+8 12 12
+4 139 15
+2 113 23
+execute stmt;
+a s m
+8 12 12
+1 50 20
+2 113 23
+7 110 10
+2 113 23
+7 110 10
+8 12 12
+4 139 15
+2 113 23
+deallocate prepare stmt;
+delete from t1 where t1.b between 2 and 5;
+set statement optimizer_switch='split_materialized=off' for select t1.a,t.max,t.min
from t1 left join
(select a, max(t2.b) max, min(t2.b) min from t2 group by t2.a) t
on t1.a=t.a;
a max min
-8 12 12
5 NULL NULL
-1 30 20
2 90 23
9 NULL NULL
-7 82 10
-2 90 23
-7 82 10
+8 12 12
select t1.a,t.max,t.min
from t1 left join
(select a, max(t2.b) max, min(t2.b) min from t2 group by t2.a) t
on t1.a=t.a;
a max min
-8 12 12
5 NULL NULL
-1 30 20
2 90 23
9 NULL NULL
-7 82 10
-2 90 23
-7 82 10
+8 12 12
explain extended select t1.a,t.max,t.min
from t1 left join
(select a, max(t2.b) max, min(t2.b) min from t2 group by t2.a) t
on t1.a=t.a;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY t1 ALL NULL NULL NULL NULL 8 100.00
+1 PRIMARY t1 ALL NULL NULL NULL NULL 4 100.00
1 PRIMARY <derived2> ref key0 key0 5 test.t1.a 2 100.00 Using where
-2 LATERAL DERIVED t2 ref idx idx 5 test.t1.a 2 100.00
+2 LATERAL DERIVED t2 ref idx_a idx_a 5 test.t1.a 2 100.00
Warnings:
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`t`.`max` AS `max`,`t`.`min` AS `min` from `test`.`t1` left join (/* select#2 */ select `test`.`t2`.`a` AS `a`,max(`test`.`t2`.`b`) AS `max`,min(`test`.`t2`.`b`) AS `min` from `test`.`t2` where `test`.`t2`.`a` = `test`.`t1`.`a` group by `test`.`t2`.`a`) `t` on(`t`.`a` = `test`.`t1`.`a` and `test`.`t1`.`a` is not null) where 1
explain format=json select t1.a,t.max,t.min
@@ -13377,7 +13521,7 @@ EXPLAIN
"table": {
"table_name": "t1",
"access_type": "ALL",
- "rows": 8,
+ "rows": 4,
"filtered": 100
},
"table": {
@@ -13398,8 +13542,8 @@ EXPLAIN
"table": {
"table_name": "t2",
"access_type": "ref",
- "possible_keys": ["idx"],
- "key": "idx",
+ "possible_keys": ["idx_a"],
+ "key": "idx_a",
"key_length": "5",
"used_key_parts": ["a"],
"ref": ["test.t1.a"],
@@ -13411,53 +13555,68 @@ EXPLAIN
}
}
}
-create table t3 (a int, c varchar(16));
+create table t3 (a int, b int, c char(127), index idx_b(b)) engine=myisam;
insert into t3 values
-(8,'aa'), (5,'cc'), (1,'bb'), (2,'aa'), (9,'cc'),
-(7,'aa'), (2,'aa'), (7,'bb');
-create table t4 (a int, b int, c varchar(16), index idx(a,c));
+(8,11,'aa'), (5,15,'cc'), (1,14,'bb'), (2,12,'aa'), (7,17,'cc'),
+(7,18,'aa'), (2,11,'aa'), (7,10,'bb'), (3,11,'dd'), (4,12,'ee'),
+(5,14,'dd'), (9,12,'ee');
+create table t4 (a int, b int, c char(127), index idx(a,c)) engine=myisam;
insert into t4 values
(7,10,'cc'), (1,20,'aa'), (2,23,'bb'), (7,18,'cc'), (1,30,'bb'),
-(4,71,'xx'), (3,15,'aa'), (7,82,'bb'), (8,12,'dd'), (4,15,'aa'),
-(11,33,'yy'), (10,42,'zz'), (4,53,'xx'), (10,17,'yy'), (7,12,'bb'),
+(4,71,'xx'), (3,15,'aa'), (7,82,'aa'), (8,12,'dd'), (4,15,'aa'),
+(11,33,'yy'), (10,42,'zz'), (4,53,'xx'), (10,17,'yy'), (7,12,'cc'),
(8,20,'dd'), (7,32,'bb'), (1,50,'aa'), (3,40,'bb'), (3,77,'aa');
-set statement optimizer_switch='split_grouping_derived=off' for select t3.a,t3.c,t.max,t.min
+insert into t4 select a+10, b+10, concat(c,'f') from t4;
+analyze table t3,t4;
+Table Op Msg_type Msg_text
+test.t3 analyze status OK
+test.t4 analyze status OK
+set statement optimizer_switch='split_materialized=off' for select t3.a,t3.c,t.max,t.min
from t3 join
(select a, c, max(b) max, min(b) min from t4 group by a,c) t
-on t3.a=t.a and t3.c=t.c;
+on t3.a=t.a and t3.c=t.c
+where t3.b > 15;
a c max min
-1 bb 30 30
-7 bb 82 12
+7 cc 18 10
+7 aa 82 82
select t3.a,t3.c,t.max,t.min
from t3 join
(select a, c, max(b) max, min(b) min from t4 group by a,c) t
-on t3.a=t.a and t3.c=t.c;
+on t3.a=t.a and t3.c=t.c
+where t3.b > 15;
a c max min
-1 bb 30 30
-7 bb 82 12
+7 cc 18 10
+7 aa 82 82
explain extended select t3.a,t3.c,t.max,t.min
from t3 join
(select a, c, max(b) max, min(b) min from t4 group by a,c) t
-on t3.a=t.a and t3.c=t.c;
+on t3.a=t.a and t3.c=t.c
+where t3.b > 15;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY t3 ALL NULL NULL NULL NULL 8 100.00 Using where
-1 PRIMARY <derived2> ref key0 key0 24 test.t3.a,test.t3.c 2 100.00
-2 LATERAL DERIVED t4 ref idx idx 24 test.t3.a,test.t3.c 2 100.00
+1 PRIMARY t3 range idx_b idx_b 5 NULL 3 100.00 Using index condition; Using where
+1 PRIMARY <derived2> ref key0 key0 133 test.t3.a,test.t3.c 2 100.00
+2 LATERAL DERIVED t4 ref idx idx 133 test.t3.a,test.t3.c 1 100.00
Warnings:
-Note 1003 /* select#1 */ select `test`.`t3`.`a` AS `a`,`test`.`t3`.`c` AS `c`,`t`.`max` AS `max`,`t`.`min` AS `min` from `test`.`t3` join (/* select#2 */ select `test`.`t4`.`a` AS `a`,`test`.`t4`.`c` AS `c`,max(`test`.`t4`.`b`) AS `max`,min(`test`.`t4`.`b`) AS `min` from `test`.`t4` where `test`.`t4`.`a` = `test`.`t3`.`a` and `test`.`t4`.`c` = `test`.`t3`.`c` group by `test`.`t4`.`a`,`test`.`t4`.`c`) `t` where `t`.`a` = `test`.`t3`.`a` and `t`.`c` = `test`.`t3`.`c`
+Note 1003 /* select#1 */ select `test`.`t3`.`a` AS `a`,`test`.`t3`.`c` AS `c`,`t`.`max` AS `max`,`t`.`min` AS `min` from `test`.`t3` join (/* select#2 */ select `test`.`t4`.`a` AS `a`,`test`.`t4`.`c` AS `c`,max(`test`.`t4`.`b`) AS `max`,min(`test`.`t4`.`b`) AS `min` from `test`.`t4` where `test`.`t4`.`a` = `test`.`t3`.`a` and `test`.`t4`.`c` = `test`.`t3`.`c` group by `test`.`t4`.`a`,`test`.`t4`.`c`) `t` where `t`.`a` = `test`.`t3`.`a` and `t`.`c` = `test`.`t3`.`c` and `test`.`t3`.`b` > 15
explain format=json select t3.a,t3.c,t.max,t.min
from t3 join
(select a, c, max(b) max, min(b) min from t4 group by a,c) t
-on t3.a=t.a and t3.c=t.c;
+on t3.a=t.a and t3.c=t.c
+where t3.b > 15;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t3",
- "access_type": "ALL",
- "rows": 8,
+ "access_type": "range",
+ "possible_keys": ["idx_b"],
+ "key": "idx_b",
+ "key_length": "5",
+ "used_key_parts": ["b"],
+ "rows": 3,
"filtered": 100,
+ "index_condition": "t3.b > 15",
"attached_condition": "t3.a is not null and t3.c is not null"
},
"table": {
@@ -13465,7 +13624,7 @@ EXPLAIN
"access_type": "ref",
"possible_keys": ["key0"],
"key": "key0",
- "key_length": "24",
+ "key_length": "133",
"used_key_parts": ["a", "c"],
"ref": ["test.t3.a", "test.t3.c"],
"rows": 2,
@@ -13479,10 +13638,10 @@ EXPLAIN
"access_type": "ref",
"possible_keys": ["idx"],
"key": "idx",
- "key_length": "24",
+ "key_length": "133",
"used_key_parts": ["a", "c"],
"ref": ["test.t3.a", "test.t3.c"],
- "rows": 2,
+ "rows": 1,
"filtered": 100
}
}
@@ -13490,43 +13649,126 @@ EXPLAIN
}
}
}
-set statement optimizer_switch='split_grouping_derived=off' for select t3.a,t3.c,t.max,t.min
+set statement optimizer_switch='split_materialized=off' for select t3.a,t3.c,t.max,t.min
from t3 join
-(select a, c, max(b) max, min(b) min from t4 group by c,a) t
-on t3.a=t.a and t3.c=t.c;
+(select a, c, max(b) max, min(b) min from t4 group by a,c) t
+on t3.a=t.a and t3.c=t.c
+where t3.b <= 15;
a c max min
1 bb 30 30
-7 bb 82 12
+7 bb 32 32
select t3.a,t3.c,t.max,t.min
from t3 join
-(select a, c, max(b) max, min(b) min from t4 group by c,a) t
-on t3.a=t.a and t3.c=t.c;
+(select a, c, max(b) max, min(b) min from t4 group by a,c) t
+on t3.a=t.a and t3.c=t.c
+where t3.b <= 15;
a c max min
1 bb 30 30
-7 bb 82 12
+7 bb 32 32
+explain extended select t3.a,t3.c,t.max,t.min
+from t3 join
+(select a, c, max(b) max, min(b) min from t4 group by a,c) t
+on t3.a=t.a and t3.c=t.c
+where t3.b <= 15;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t3 ALL idx_b NULL NULL NULL 12 75.00 Using where
+1 PRIMARY <derived2> ref key0 key0 133 test.t3.a,test.t3.c 4 100.00
+2 DERIVED t4 ALL idx NULL NULL NULL 40 100.00 Using temporary; Using filesort
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t3`.`a` AS `a`,`test`.`t3`.`c` AS `c`,`t`.`max` AS `max`,`t`.`min` AS `min` from `test`.`t3` join (/* select#2 */ select `test`.`t4`.`a` AS `a`,`test`.`t4`.`c` AS `c`,max(`test`.`t4`.`b`) AS `max`,min(`test`.`t4`.`b`) AS `min` from `test`.`t4` group by `test`.`t4`.`a`,`test`.`t4`.`c`) `t` where `t`.`a` = `test`.`t3`.`a` and `t`.`c` = `test`.`t3`.`c` and `test`.`t3`.`b` <= 15
+explain format=json select t3.a,t3.c,t.max,t.min
+from t3 join
+(select a, c, max(b) max, min(b) min from t4 group by a,c) t
+on t3.a=t.a and t3.c=t.c
+where t3.b <= 15;
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "table": {
+ "table_name": "t3",
+ "access_type": "ALL",
+ "possible_keys": ["idx_b"],
+ "rows": 12,
+ "filtered": 75,
+ "attached_condition": "t3.b <= 15 and t3.a is not null and t3.c is not null"
+ },
+ "table": {
+ "table_name": "<derived2>",
+ "access_type": "ref",
+ "possible_keys": ["key0"],
+ "key": "key0",
+ "key_length": "133",
+ "used_key_parts": ["a", "c"],
+ "ref": ["test.t3.a", "test.t3.c"],
+ "rows": 4,
+ "filtered": 100,
+ "materialized": {
+ "query_block": {
+ "select_id": 2,
+ "filesort": {
+ "sort_key": "t4.a, t4.c",
+ "temporary_table": {
+ "table": {
+ "table_name": "t4",
+ "access_type": "ALL",
+ "possible_keys": ["idx"],
+ "rows": 40,
+ "filtered": 100
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='split_materialized=off' for select t3.a,t3.c,t.max,t.min
+from t3 join
+(select a, c, max(b) max, min(b) min from t4 group by c,a) t
+on t3.a=t.a and t3.c=t.c
+where t3.b > 15;
+a c max min
+7 cc 18 10
+7 aa 82 82
+select t3.a,t3.c,t.max,t.min
+from t3 join
+(select a, c, max(b) max, min(b) min from t4 group by c,a) t
+on t3.a=t.a and t3.c=t.c
+where t3.b > 15;
+a c max min
+7 cc 18 10
+7 aa 82 82
explain extended select t3.a,t3.c,t.max,t.min
from t3 join
(select a, c, max(b) max, min(b) min from t4 group by c,a) t
-on t3.a=t.a and t3.c=t.c;
+on t3.a=t.a and t3.c=t.c
+where t3.b > 15;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY t3 ALL NULL NULL NULL NULL 8 100.00 Using where
-1 PRIMARY <derived2> ref key0 key0 24 test.t3.a,test.t3.c 2 100.00
-2 LATERAL DERIVED t4 ref idx idx 24 test.t3.a,test.t3.c 2 100.00
+1 PRIMARY t3 range idx_b idx_b 5 NULL 3 100.00 Using index condition; Using where
+1 PRIMARY <derived2> ref key0 key0 133 test.t3.a,test.t3.c 2 100.00
+2 LATERAL DERIVED t4 ref idx idx 133 test.t3.a,test.t3.c 1 100.00
Warnings:
-Note 1003 /* select#1 */ select `test`.`t3`.`a` AS `a`,`test`.`t3`.`c` AS `c`,`t`.`max` AS `max`,`t`.`min` AS `min` from `test`.`t3` join (/* select#2 */ select `test`.`t4`.`a` AS `a`,`test`.`t4`.`c` AS `c`,max(`test`.`t4`.`b`) AS `max`,min(`test`.`t4`.`b`) AS `min` from `test`.`t4` where `test`.`t4`.`c` = `test`.`t3`.`c` and `test`.`t4`.`a` = `test`.`t3`.`a` group by `test`.`t4`.`c`,`test`.`t4`.`a`) `t` where `t`.`a` = `test`.`t3`.`a` and `t`.`c` = `test`.`t3`.`c`
+Note 1003 /* select#1 */ select `test`.`t3`.`a` AS `a`,`test`.`t3`.`c` AS `c`,`t`.`max` AS `max`,`t`.`min` AS `min` from `test`.`t3` join (/* select#2 */ select `test`.`t4`.`a` AS `a`,`test`.`t4`.`c` AS `c`,max(`test`.`t4`.`b`) AS `max`,min(`test`.`t4`.`b`) AS `min` from `test`.`t4` where `test`.`t4`.`a` = `test`.`t3`.`a` and `test`.`t4`.`c` = `test`.`t3`.`c` group by `test`.`t4`.`c`,`test`.`t4`.`a`) `t` where `t`.`a` = `test`.`t3`.`a` and `t`.`c` = `test`.`t3`.`c` and `test`.`t3`.`b` > 15
explain format=json select t3.a,t3.c,t.max,t.min
from t3 join
(select a, c, max(b) max, min(b) min from t4 group by c,a) t
-on t3.a=t.a and t3.c=t.c;
+on t3.a=t.a and t3.c=t.c
+where t3.b > 15;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t3",
- "access_type": "ALL",
- "rows": 8,
+ "access_type": "range",
+ "possible_keys": ["idx_b"],
+ "key": "idx_b",
+ "key_length": "5",
+ "used_key_parts": ["b"],
+ "rows": 3,
"filtered": 100,
+ "index_condition": "t3.b > 15",
"attached_condition": "t3.a is not null and t3.c is not null"
},
"table": {
@@ -13534,7 +13776,7 @@ EXPLAIN
"access_type": "ref",
"possible_keys": ["key0"],
"key": "key0",
- "key_length": "24",
+ "key_length": "133",
"used_key_parts": ["a", "c"],
"ref": ["test.t3.a", "test.t3.c"],
"rows": 2,
@@ -13548,10 +13790,10 @@ EXPLAIN
"access_type": "ref",
"possible_keys": ["idx"],
"key": "idx",
- "key_length": "24",
+ "key_length": "133",
"used_key_parts": ["a", "c"],
"ref": ["test.t3.a", "test.t3.c"],
- "rows": 2,
+ "rows": 1,
"filtered": 100
}
}
@@ -13559,44 +13801,120 @@ EXPLAIN
}
}
}
-drop index idx on t2;
-create index idx on t2(b);
-create index idx on t3(a);
-create index idx2 on t4(c);
-insert into t3 select a+1, concat(c,'f') from t3;
-insert into t3 select a+1, concat(c,'h') from t3;
-insert into t4 select a+1, b+10, concat(c,'h') from t4;
-set statement optimizer_switch='split_grouping_derived=off' for select t2.a,t2.b,t3.c,t.max,t.min
+set statement optimizer_switch='split_materialized=off' for select t3.a,t3.c,t.max,t.min
+from t3 join
+(select a, c, max(b) max, min(b) min from t4 group by c,a) t
+on t3.a=t.a and t3.c=t.c
+where t3.b <= 15;
+a c max min
+1 bb 30 30
+7 bb 32 32
+select t3.a,t3.c,t.max,t.min
+from t3 join
+(select a, c, max(b) max, min(b) min from t4 group by c,a) t
+on t3.a=t.a and t3.c=t.c
+where t3.b <= 15;
+a c max min
+1 bb 30 30
+7 bb 32 32
+explain extended select t3.a,t3.c,t.max,t.min
+from t3 join
+(select a, c, max(b) max, min(b) min from t4 group by c,a) t
+on t3.a=t.a and t3.c=t.c
+where t3.b <= 15;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t3 ALL idx_b NULL NULL NULL 12 75.00 Using where
+1 PRIMARY <derived2> ref key0 key0 133 test.t3.a,test.t3.c 4 100.00
+2 DERIVED t4 ALL idx NULL NULL NULL 40 100.00 Using temporary; Using filesort
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t3`.`a` AS `a`,`test`.`t3`.`c` AS `c`,`t`.`max` AS `max`,`t`.`min` AS `min` from `test`.`t3` join (/* select#2 */ select `test`.`t4`.`a` AS `a`,`test`.`t4`.`c` AS `c`,max(`test`.`t4`.`b`) AS `max`,min(`test`.`t4`.`b`) AS `min` from `test`.`t4` group by `test`.`t4`.`c`,`test`.`t4`.`a`) `t` where `t`.`a` = `test`.`t3`.`a` and `t`.`c` = `test`.`t3`.`c` and `test`.`t3`.`b` <= 15
+explain format=json select t3.a,t3.c,t.max,t.min
+from t3 join
+(select a, c, max(b) max, min(b) min from t4 group by c,a) t
+on t3.a=t.a and t3.c=t.c
+where t3.b <= 15;
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "table": {
+ "table_name": "t3",
+ "access_type": "ALL",
+ "possible_keys": ["idx_b"],
+ "rows": 12,
+ "filtered": 75,
+ "attached_condition": "t3.b <= 15 and t3.a is not null and t3.c is not null"
+ },
+ "table": {
+ "table_name": "<derived2>",
+ "access_type": "ref",
+ "possible_keys": ["key0"],
+ "key": "key0",
+ "key_length": "133",
+ "used_key_parts": ["a", "c"],
+ "ref": ["test.t3.a", "test.t3.c"],
+ "rows": 4,
+ "filtered": 100,
+ "materialized": {
+ "query_block": {
+ "select_id": 2,
+ "filesort": {
+ "sort_key": "t4.c, t4.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t4",
+ "access_type": "ALL",
+ "possible_keys": ["idx"],
+ "rows": 40,
+ "filtered": 100
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+drop index idx_a on t2;
+create index idx on t2(c,b);
+create index idx_a on t3(a);
+create index idx_c on t4(c);
+insert into t3 select a+10, b+10, concat(c,'f') from t3;
+insert into t3 select a+100, b+100, concat(c,'g') from t3;
+insert into t4 select a+100, b+100, concat(c,'g') from t4;
+insert into t4 select a+1000, b+1000, concat(c,'h') from t4;
+analyze table t2,t3,t4;
+Table Op Msg_type Msg_text
+test.t2 analyze status OK
+test.t3 analyze status OK
+test.t4 analyze status OK
+set statement optimizer_switch='split_materialized=off' for select t2.a,t2.b,t2.c,t.c as t_c,t.max,t.min
from t2, t3, (select c, max(b) max, min(b) min from t4 group by c) t
-where t2.b > 50 and t2.a=t3.a and t3.c=t.c;
-a b c max min
-7 82 aa 77 15
-7 82 bb 82 12
-2 90 aa 77 15
-2 90 aa 77 15
-2 90 bbh 92 22
-select t2.a,t2.b,t3.c,t.max,t.min
+where t2.b between 80 and 85 and t2.c in ('y','z') and t2.a=t3.a and t3.c=t.c;
+a b c t_c max min
+7 82 y cc 18 10
+7 82 y aa 82 15
+7 82 y bb 40 23
+select t2.a,t2.b,t2.c,t.c as t_c,t.max,t.min
from t2, t3, (select c, max(b) max, min(b) min from t4 group by c) t
-where t2.b > 50 and t2.a=t3.a and t3.c=t.c;
-a b c max min
-7 82 aa 77 15
-7 82 bb 82 12
-2 90 aa 77 15
-2 90 aa 77 15
-2 90 bbh 92 22
-explain extended select t2.a,t2.b,t3.c,t.max,t.min
+where t2.b between 80 and 85 and t2.c in ('y','z') and t2.a=t3.a and t3.c=t.c;
+a b c t_c max min
+7 82 y cc 18 10
+7 82 y aa 82 15
+7 82 y bb 40 23
+explain extended select t2.a,t2.b,t2.c,t.c as t_c,t.max,t.min
from t2, t3, (select c, max(b) max, min(b) min from t4 group by c) t
-where t2.b > 50 and t2.a=t3.a and t3.c=t.c;
+where t2.b between 80 and 85 and t2.c in ('y','z') and t2.a=t3.a and t3.c=t.c;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY t2 range idx idx 5 NULL 5 100.00 Using index condition; Using where
-1 PRIMARY t3 ref idx idx 5 test.t2.a 3 100.00 Using where
-1 PRIMARY <derived2> ref key0 key0 19 test.t3.c 4 100.00
-2 LATERAL DERIVED t4 ref idx2 idx2 19 test.t3.c 5 100.00
+1 PRIMARY t2 range idx idx 133 NULL 2 100.00 Using index condition; Using where
+1 PRIMARY t3 ref idx_a idx_a 5 test.t2.a 2 100.00 Using where
+1 PRIMARY <derived2> ref key0 key0 128 test.t3.c 2 100.00
+2 LATERAL DERIVED t4 ref idx_c idx_c 128 test.t3.c 3 100.00
Warnings:
-Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`c` AS `c`,`t`.`max` AS `max`,`t`.`min` AS `min` from `test`.`t2` join `test`.`t3` join (/* select#2 */ select `test`.`t4`.`c` AS `c`,max(`test`.`t4`.`b`) AS `max`,min(`test`.`t4`.`b`) AS `min` from `test`.`t4` where `test`.`t4`.`c` = `test`.`t3`.`c` group by `test`.`t4`.`c`) `t` where `test`.`t3`.`a` = `test`.`t2`.`a` and `t`.`c` = `test`.`t3`.`c` and `test`.`t2`.`b` > 50
-explain format=json select t2.a,t2.b,t3.c,t.max,t.min
+Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c`,`t`.`c` AS `t_c`,`t`.`max` AS `max`,`t`.`min` AS `min` from `test`.`t2` join `test`.`t3` join (/* select#2 */ select `test`.`t4`.`c` AS `c`,max(`test`.`t4`.`b`) AS `max`,min(`test`.`t4`.`b`) AS `min` from `test`.`t4` where `test`.`t4`.`c` = `test`.`t3`.`c` group by `test`.`t4`.`c`) `t` where `test`.`t3`.`a` = `test`.`t2`.`a` and `t`.`c` = `test`.`t3`.`c` and `test`.`t2`.`b` between 80 and 85 and `test`.`t2`.`c` in ('y','z')
+explain format=json select t2.a,t2.b,t2.c,t.c as t_c,t.max,t.min
from t2, t3, (select c, max(b) max, min(b) min from t4 group by c) t
-where t2.b > 50 and t2.a=t3.a and t3.c=t.c;
+where t2.b between 80 and 85 and t2.c in ('y','z') and t2.a=t3.a and t3.c=t.c;
EXPLAIN
{
"query_block": {
@@ -13606,22 +13924,22 @@ EXPLAIN
"access_type": "range",
"possible_keys": ["idx"],
"key": "idx",
- "key_length": "5",
- "used_key_parts": ["b"],
- "rows": 5,
+ "key_length": "133",
+ "used_key_parts": ["c", "b"],
+ "rows": 2,
"filtered": 100,
- "index_condition": "t2.b > 50",
+ "index_condition": "t2.b between 80 and 85 and t2.c in ('y','z')",
"attached_condition": "t2.a is not null"
},
"table": {
"table_name": "t3",
"access_type": "ref",
- "possible_keys": ["idx"],
- "key": "idx",
+ "possible_keys": ["idx_a"],
+ "key": "idx_a",
"key_length": "5",
"used_key_parts": ["a"],
"ref": ["test.t2.a"],
- "rows": 3,
+ "rows": 2,
"filtered": 100,
"attached_condition": "t3.c is not null"
},
@@ -13630,10 +13948,10 @@ EXPLAIN
"access_type": "ref",
"possible_keys": ["key0"],
"key": "key0",
- "key_length": "19",
+ "key_length": "128",
"used_key_parts": ["c"],
"ref": ["test.t3.c"],
- "rows": 4,
+ "rows": 2,
"filtered": 100,
"materialized": {
"query_block": {
@@ -13642,12 +13960,12 @@ EXPLAIN
"table": {
"table_name": "t4",
"access_type": "ref",
- "possible_keys": ["idx2"],
- "key": "idx2",
- "key_length": "19",
+ "possible_keys": ["idx_c"],
+ "key": "idx_c",
+ "key_length": "128",
"used_key_parts": ["c"],
"ref": ["test.t3.c"],
- "rows": 5,
+ "rows": 3,
"filtered": 100
}
}
@@ -13655,81 +13973,195 @@ EXPLAIN
}
}
}
-set statement optimizer_switch='split_grouping_derived=off' for select *
+set statement optimizer_switch='split_materialized=off' for select t2.a,t2.b,t2.c,t.c as t_c,t.max,t.min
+from t2, t3, (select c, max(b) max, min(b) min from t4 group by c) t
+where t2.b < 40 and t2.a=t3.a and t3.c=t.c;
+a b c t_c max min
+7 10 x cc 18 10
+7 10 x aa 82 15
+7 10 x bb 40 23
+1 20 a bb 40 23
+2 23 b aa 82 15
+2 23 b aa 82 15
+7 18 z cc 18 10
+7 18 z aa 82 15
+7 18 z bb 40 23
+1 30 c bb 40 23
+3 15 x dd 20 12
+8 12 t aa 82 15
+11 33 a bbf 50 33
+17 10 s ccf 28 20
+17 10 s aaf 92 25
+17 10 s bbf 50 33
+11 20 v bbf 50 33
+12 23 y aaf 92 25
+12 23 y aaf 92 25
+17 18 a ccf 28 20
+17 18 a aaf 92 25
+17 18 a bbf 50 33
+11 30 d bbf 50 33
+17 20 xf ccf 28 20
+17 20 xf aaf 92 25
+17 20 xf bbf 50 33
+11 30 af bbf 50 33
+12 33 bf aaf 92 25
+12 33 bf aaf 92 25
+17 28 zf ccf 28 20
+17 28 zf aaf 92 25
+17 28 zf bbf 50 33
+13 25 xf ddf 30 22
+18 22 tf aaf 92 25
+select t2.a,t2.b,t2.c,t.c as t_c,t.max,t.min
+from t2, t3, (select c, max(b) max, min(b) min from t4 group by c) t
+where t2.b < 40 and t2.a=t3.a and t3.c=t.c;
+a b c t_c max min
+7 10 x cc 18 10
+7 10 x aa 82 15
+7 10 x bb 40 23
+1 20 a bb 40 23
+2 23 b aa 82 15
+2 23 b aa 82 15
+7 18 z cc 18 10
+7 18 z aa 82 15
+7 18 z bb 40 23
+1 30 c bb 40 23
+3 15 x dd 20 12
+8 12 t aa 82 15
+11 33 a bbf 50 33
+17 10 s ccf 28 20
+17 10 s aaf 92 25
+17 10 s bbf 50 33
+11 20 v bbf 50 33
+12 23 y aaf 92 25
+12 23 y aaf 92 25
+17 18 a ccf 28 20
+17 18 a aaf 92 25
+17 18 a bbf 50 33
+11 30 d bbf 50 33
+17 20 xf ccf 28 20
+17 20 xf aaf 92 25
+17 20 xf bbf 50 33
+11 30 af bbf 50 33
+12 33 bf aaf 92 25
+12 33 bf aaf 92 25
+17 28 zf ccf 28 20
+17 28 zf aaf 92 25
+17 28 zf bbf 50 33
+13 25 xf ddf 30 22
+18 22 tf aaf 92 25
+explain extended select t2.a,t2.b,t2.c,t.c as t_c,t.max,t.min
+from t2, t3, (select c, max(b) max, min(b) min from t4 group by c) t
+where t2.b < 40 and t2.a=t3.a and t3.c=t.c;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t2 ALL NULL NULL NULL NULL 90 100.00 Using where
+1 PRIMARY t3 ref idx_a idx_a 5 test.t2.a 2 100.00 Using where
+1 PRIMARY <derived2> ref key0 key0 128 test.t3.c 10 100.00
+2 DERIVED t4 ALL idx_c NULL NULL NULL 160 100.00 Using temporary; Using filesort
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c`,`t`.`c` AS `t_c`,`t`.`max` AS `max`,`t`.`min` AS `min` from `test`.`t2` join `test`.`t3` join (/* select#2 */ select `test`.`t4`.`c` AS `c`,max(`test`.`t4`.`b`) AS `max`,min(`test`.`t4`.`b`) AS `min` from `test`.`t4` group by `test`.`t4`.`c`) `t` where `test`.`t3`.`a` = `test`.`t2`.`a` and `t`.`c` = `test`.`t3`.`c` and `test`.`t2`.`b` < 40
+explain format=json select t2.a,t2.b,t2.c,t.c as t_c,t.max,t.min
+from t2, t3, (select c, max(b) max, min(b) min from t4 group by c) t
+where t2.b < 40 and t2.a=t3.a and t3.c=t.c;
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "rows": 90,
+ "filtered": 100,
+ "attached_condition": "t2.b < 40 and t2.a is not null"
+ },
+ "table": {
+ "table_name": "t3",
+ "access_type": "ref",
+ "possible_keys": ["idx_a"],
+ "key": "idx_a",
+ "key_length": "5",
+ "used_key_parts": ["a"],
+ "ref": ["test.t2.a"],
+ "rows": 2,
+ "filtered": 100,
+ "attached_condition": "t3.c is not null"
+ },
+ "table": {
+ "table_name": "<derived2>",
+ "access_type": "ref",
+ "possible_keys": ["key0"],
+ "key": "key0",
+ "key_length": "128",
+ "used_key_parts": ["c"],
+ "ref": ["test.t3.c"],
+ "rows": 10,
+ "filtered": 100,
+ "materialized": {
+ "query_block": {
+ "select_id": 2,
+ "filesort": {
+ "sort_key": "t4.c",
+ "temporary_table": {
+ "table": {
+ "table_name": "t4",
+ "access_type": "ALL",
+ "possible_keys": ["idx_c"],
+ "rows": 160,
+ "filtered": 100
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='split_materialized=off' for select *
from t2, t3, (select c, b, sum(b) over (partition by c) from t4 ) t
-where t2.b > 50 and t2.a=t3.a and t3.c=t.c;
-a b a c c b sum(b) over (partition by c)
-7 82 7 aa aa 77 177
-7 82 7 aa aa 50 177
-7 82 7 aa aa 15 177
-7 82 7 aa aa 15 177
-7 82 7 aa aa 20 177
-7 82 7 bb bb 40 219
-7 82 7 bb bb 32 219
-7 82 7 bb bb 12 219
-7 82 7 bb bb 82 219
-7 82 7 bb bb 30 219
-7 82 7 bb bb 23 219
-2 90 2 aa aa 77 177
-2 90 2 aa aa 50 177
-2 90 2 aa aa 15 177
-2 90 2 aa aa 15 177
-2 90 2 aa aa 20 177
-2 90 2 aa aa 77 177
-2 90 2 aa aa 50 177
-2 90 2 aa aa 15 177
-2 90 2 aa aa 15 177
-2 90 2 aa aa 20 177
-2 90 2 bbh bbh 50 279
-2 90 2 bbh bbh 42 279
-2 90 2 bbh bbh 22 279
-2 90 2 bbh bbh 92 279
-2 90 2 bbh bbh 40 279
-2 90 2 bbh bbh 33 279
+where t2.b between 80 and 85 and t2.c in ('y','z') and t2.a=t3.a and t3.c=t.c;
+a b c a b c c b sum(b) over (partition by c)
+7 82 y 7 17 cc cc 12 40
+7 82 y 7 17 cc cc 18 40
+7 82 y 7 17 cc cc 10 40
+7 82 y 7 18 aa aa 77 259
+7 82 y 7 18 aa aa 50 259
+7 82 y 7 18 aa aa 15 259
+7 82 y 7 18 aa aa 82 259
+7 82 y 7 18 aa aa 15 259
+7 82 y 7 18 aa aa 20 259
+7 82 y 7 10 bb bb 40 125
+7 82 y 7 10 bb bb 32 125
+7 82 y 7 10 bb bb 30 125
+7 82 y 7 10 bb bb 23 125
select *
from t2, t3, (select c, b, sum(b) over (partition by c) from t4 ) t
-where t2.b > 50 and t2.a=t3.a and t3.c=t.c;
-a b a c c b sum(b) over (partition by c)
-7 82 7 aa aa 77 177
-7 82 7 aa aa 50 177
-7 82 7 aa aa 15 177
-7 82 7 aa aa 15 177
-7 82 7 aa aa 20 177
-7 82 7 bb bb 40 219
-7 82 7 bb bb 32 219
-7 82 7 bb bb 12 219
-7 82 7 bb bb 82 219
-7 82 7 bb bb 30 219
-7 82 7 bb bb 23 219
-2 90 2 aa aa 77 177
-2 90 2 aa aa 50 177
-2 90 2 aa aa 15 177
-2 90 2 aa aa 15 177
-2 90 2 aa aa 20 177
-2 90 2 aa aa 77 177
-2 90 2 aa aa 50 177
-2 90 2 aa aa 15 177
-2 90 2 aa aa 15 177
-2 90 2 aa aa 20 177
-2 90 2 bbh bbh 50 279
-2 90 2 bbh bbh 42 279
-2 90 2 bbh bbh 22 279
-2 90 2 bbh bbh 92 279
-2 90 2 bbh bbh 40 279
-2 90 2 bbh bbh 33 279
+where t2.b between 80 and 85 and t2.c in ('y','z') and t2.a=t3.a and t3.c=t.c;
+a b c a b c c b sum(b) over (partition by c)
+7 82 y 7 17 cc cc 12 40
+7 82 y 7 17 cc cc 18 40
+7 82 y 7 17 cc cc 10 40
+7 82 y 7 18 aa aa 77 259
+7 82 y 7 18 aa aa 50 259
+7 82 y 7 18 aa aa 15 259
+7 82 y 7 18 aa aa 82 259
+7 82 y 7 18 aa aa 15 259
+7 82 y 7 18 aa aa 20 259
+7 82 y 7 10 bb bb 40 125
+7 82 y 7 10 bb bb 32 125
+7 82 y 7 10 bb bb 30 125
+7 82 y 7 10 bb bb 23 125
explain extended select *
from t2, t3, (select c, b, sum(b) over (partition by c) from t4 ) t
-where t2.b > 50 and t2.a=t3.a and t3.c=t.c;
+where t2.b between 80 and 85 and t2.c in ('y','z') and t2.a=t3.a and t3.c=t.c;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY t2 range idx idx 5 NULL 5 100.00 Using index condition; Using where
-1 PRIMARY t3 ref idx idx 5 test.t2.a 3 100.00 Using where
-1 PRIMARY <derived2> ref key0 key0 19 test.t3.c 4 100.00
-2 LATERAL DERIVED t4 ref idx2 idx2 19 test.t3.c 5 100.00 Using temporary
+1 PRIMARY t2 range idx idx 133 NULL 2 100.00 Using index condition; Using where
+1 PRIMARY t3 ref idx_a idx_a 5 test.t2.a 2 100.00 Using where
+1 PRIMARY <derived2> ref key0 key0 128 test.t3.c 2 100.00
+2 LATERAL DERIVED t4 ref idx_c idx_c 128 test.t3.c 3 100.00 Using temporary
Warnings:
-Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`c` AS `c`,`t`.`c` AS `c`,`t`.`b` AS `b`,`t`.`sum(b) over (partition by c)` AS `sum(b) over (partition by c)` from `test`.`t2` join `test`.`t3` join (/* select#2 */ select `test`.`t4`.`c` AS `c`,`test`.`t4`.`b` AS `b`,sum(`test`.`t4`.`b`) over ( partition by `test`.`t4`.`c`) AS `sum(b) over (partition by c)` from `test`.`t4` where `test`.`t4`.`c` = `test`.`t3`.`c`) `t` where `test`.`t3`.`a` = `test`.`t2`.`a` and `t`.`c` = `test`.`t3`.`c` and `test`.`t2`.`b` > 50
+Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t3`.`c` AS `c`,`t`.`c` AS `c`,`t`.`b` AS `b`,`t`.`sum(b) over (partition by c)` AS `sum(b) over (partition by c)` from `test`.`t2` join `test`.`t3` join (/* select#2 */ select `test`.`t4`.`c` AS `c`,`test`.`t4`.`b` AS `b`,sum(`test`.`t4`.`b`) over ( partition by `test`.`t4`.`c`) AS `sum(b) over (partition by c)` from `test`.`t4` where `test`.`t4`.`c` = `test`.`t3`.`c`) `t` where `test`.`t3`.`a` = `test`.`t2`.`a` and `t`.`c` = `test`.`t3`.`c` and `test`.`t2`.`b` between 80 and 85 and `test`.`t2`.`c` in ('y','z')
explain format=json select *
from t2, t3, (select c, b, sum(b) over (partition by c) from t4 ) t
-where t2.b > 50 and t2.a=t3.a and t3.c=t.c;
+where t2.b between 80 and 85 and t2.c in ('y','z') and t2.a=t3.a and t3.c=t.c;
EXPLAIN
{
"query_block": {
@@ -13739,22 +14171,22 @@ EXPLAIN
"access_type": "range",
"possible_keys": ["idx"],
"key": "idx",
- "key_length": "5",
- "used_key_parts": ["b"],
- "rows": 5,
+ "key_length": "133",
+ "used_key_parts": ["c", "b"],
+ "rows": 2,
"filtered": 100,
- "index_condition": "t2.b > 50",
+ "index_condition": "t2.b between 80 and 85 and t2.c in ('y','z')",
"attached_condition": "t2.a is not null"
},
"table": {
"table_name": "t3",
"access_type": "ref",
- "possible_keys": ["idx"],
- "key": "idx",
+ "possible_keys": ["idx_a"],
+ "key": "idx_a",
"key_length": "5",
"used_key_parts": ["a"],
"ref": ["test.t2.a"],
- "rows": 3,
+ "rows": 2,
"filtered": 100,
"attached_condition": "t3.c is not null"
},
@@ -13763,10 +14195,10 @@ EXPLAIN
"access_type": "ref",
"possible_keys": ["key0"],
"key": "key0",
- "key_length": "19",
+ "key_length": "128",
"used_key_parts": ["c"],
"ref": ["test.t3.c"],
- "rows": 4,
+ "rows": 2,
"filtered": 100,
"materialized": {
"query_block": {
@@ -13782,12 +14214,398 @@ EXPLAIN
"table": {
"table_name": "t4",
"access_type": "ref",
- "possible_keys": ["idx2"],
- "key": "idx2",
- "key_length": "19",
+ "possible_keys": ["idx_c"],
+ "key": "idx_c",
+ "key_length": "128",
"used_key_parts": ["c"],
"ref": ["test.t3.c"],
- "rows": 5,
+ "rows": 3,
+ "filtered": 100
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='split_materialized=off' for select *
+from t2, t3, (select c, b, sum(b) over (partition by c) from t4 ) t
+where t2.b < 40 and t2.a=t3.a and t3.c=t.c;
+a b c a b c c b sum(b) over (partition by c)
+7 10 x 7 17 cc cc 12 40
+7 10 x 7 17 cc cc 18 40
+7 10 x 7 17 cc cc 10 40
+7 10 x 7 18 aa aa 77 259
+7 10 x 7 18 aa aa 50 259
+7 10 x 7 18 aa aa 15 259
+7 10 x 7 18 aa aa 82 259
+7 10 x 7 18 aa aa 15 259
+7 10 x 7 18 aa aa 20 259
+7 10 x 7 10 bb bb 40 125
+7 10 x 7 10 bb bb 32 125
+7 10 x 7 10 bb bb 30 125
+7 10 x 7 10 bb bb 23 125
+1 20 a 1 14 bb bb 40 125
+1 20 a 1 14 bb bb 32 125
+1 20 a 1 14 bb bb 30 125
+1 20 a 1 14 bb bb 23 125
+2 23 b 2 12 aa aa 77 259
+2 23 b 2 12 aa aa 50 259
+2 23 b 2 12 aa aa 15 259
+2 23 b 2 12 aa aa 82 259
+2 23 b 2 12 aa aa 15 259
+2 23 b 2 12 aa aa 20 259
+2 23 b 2 11 aa aa 77 259
+2 23 b 2 11 aa aa 50 259
+2 23 b 2 11 aa aa 15 259
+2 23 b 2 11 aa aa 82 259
+2 23 b 2 11 aa aa 15 259
+2 23 b 2 11 aa aa 20 259
+7 18 z 7 17 cc cc 12 40
+7 18 z 7 17 cc cc 18 40
+7 18 z 7 17 cc cc 10 40
+7 18 z 7 18 aa aa 77 259
+7 18 z 7 18 aa aa 50 259
+7 18 z 7 18 aa aa 15 259
+7 18 z 7 18 aa aa 82 259
+7 18 z 7 18 aa aa 15 259
+7 18 z 7 18 aa aa 20 259
+7 18 z 7 10 bb bb 40 125
+7 18 z 7 10 bb bb 32 125
+7 18 z 7 10 bb bb 30 125
+7 18 z 7 10 bb bb 23 125
+1 30 c 1 14 bb bb 40 125
+1 30 c 1 14 bb bb 32 125
+1 30 c 1 14 bb bb 30 125
+1 30 c 1 14 bb bb 23 125
+3 15 x 3 11 dd dd 20 32
+3 15 x 3 11 dd dd 12 32
+8 12 t 8 11 aa aa 77 259
+8 12 t 8 11 aa aa 50 259
+8 12 t 8 11 aa aa 15 259
+8 12 t 8 11 aa aa 82 259
+8 12 t 8 11 aa aa 15 259
+8 12 t 8 11 aa aa 20 259
+11 33 a 11 24 bbf bbf 50 165
+11 33 a 11 24 bbf bbf 42 165
+11 33 a 11 24 bbf bbf 40 165
+11 33 a 11 24 bbf bbf 33 165
+17 10 s 17 27 ccf ccf 22 70
+17 10 s 17 27 ccf ccf 28 70
+17 10 s 17 27 ccf ccf 20 70
+17 10 s 17 28 aaf aaf 87 319
+17 10 s 17 28 aaf aaf 60 319
+17 10 s 17 28 aaf aaf 25 319
+17 10 s 17 28 aaf aaf 92 319
+17 10 s 17 28 aaf aaf 25 319
+17 10 s 17 28 aaf aaf 30 319
+17 10 s 17 20 bbf bbf 50 165
+17 10 s 17 20 bbf bbf 42 165
+17 10 s 17 20 bbf bbf 40 165
+17 10 s 17 20 bbf bbf 33 165
+11 20 v 11 24 bbf bbf 50 165
+11 20 v 11 24 bbf bbf 42 165
+11 20 v 11 24 bbf bbf 40 165
+11 20 v 11 24 bbf bbf 33 165
+12 23 y 12 22 aaf aaf 87 319
+12 23 y 12 22 aaf aaf 60 319
+12 23 y 12 22 aaf aaf 25 319
+12 23 y 12 22 aaf aaf 92 319
+12 23 y 12 22 aaf aaf 25 319
+12 23 y 12 22 aaf aaf 30 319
+12 23 y 12 21 aaf aaf 87 319
+12 23 y 12 21 aaf aaf 60 319
+12 23 y 12 21 aaf aaf 25 319
+12 23 y 12 21 aaf aaf 92 319
+12 23 y 12 21 aaf aaf 25 319
+12 23 y 12 21 aaf aaf 30 319
+17 18 a 17 27 ccf ccf 22 70
+17 18 a 17 27 ccf ccf 28 70
+17 18 a 17 27 ccf ccf 20 70
+17 18 a 17 28 aaf aaf 87 319
+17 18 a 17 28 aaf aaf 60 319
+17 18 a 17 28 aaf aaf 25 319
+17 18 a 17 28 aaf aaf 92 319
+17 18 a 17 28 aaf aaf 25 319
+17 18 a 17 28 aaf aaf 30 319
+17 18 a 17 20 bbf bbf 50 165
+17 18 a 17 20 bbf bbf 42 165
+17 18 a 17 20 bbf bbf 40 165
+17 18 a 17 20 bbf bbf 33 165
+11 30 d 11 24 bbf bbf 50 165
+11 30 d 11 24 bbf bbf 42 165
+11 30 d 11 24 bbf bbf 40 165
+11 30 d 11 24 bbf bbf 33 165
+17 20 xf 17 27 ccf ccf 22 70
+17 20 xf 17 27 ccf ccf 28 70
+17 20 xf 17 27 ccf ccf 20 70
+17 20 xf 17 28 aaf aaf 87 319
+17 20 xf 17 28 aaf aaf 60 319
+17 20 xf 17 28 aaf aaf 25 319
+17 20 xf 17 28 aaf aaf 92 319
+17 20 xf 17 28 aaf aaf 25 319
+17 20 xf 17 28 aaf aaf 30 319
+17 20 xf 17 20 bbf bbf 50 165
+17 20 xf 17 20 bbf bbf 42 165
+17 20 xf 17 20 bbf bbf 40 165
+17 20 xf 17 20 bbf bbf 33 165
+11 30 af 11 24 bbf bbf 50 165
+11 30 af 11 24 bbf bbf 42 165
+11 30 af 11 24 bbf bbf 40 165
+11 30 af 11 24 bbf bbf 33 165
+12 33 bf 12 22 aaf aaf 87 319
+12 33 bf 12 22 aaf aaf 60 319
+12 33 bf 12 22 aaf aaf 25 319
+12 33 bf 12 22 aaf aaf 92 319
+12 33 bf 12 22 aaf aaf 25 319
+12 33 bf 12 22 aaf aaf 30 319
+12 33 bf 12 21 aaf aaf 87 319
+12 33 bf 12 21 aaf aaf 60 319
+12 33 bf 12 21 aaf aaf 25 319
+12 33 bf 12 21 aaf aaf 92 319
+12 33 bf 12 21 aaf aaf 25 319
+12 33 bf 12 21 aaf aaf 30 319
+17 28 zf 17 27 ccf ccf 22 70
+17 28 zf 17 27 ccf ccf 28 70
+17 28 zf 17 27 ccf ccf 20 70
+17 28 zf 17 28 aaf aaf 87 319
+17 28 zf 17 28 aaf aaf 60 319
+17 28 zf 17 28 aaf aaf 25 319
+17 28 zf 17 28 aaf aaf 92 319
+17 28 zf 17 28 aaf aaf 25 319
+17 28 zf 17 28 aaf aaf 30 319
+17 28 zf 17 20 bbf bbf 50 165
+17 28 zf 17 20 bbf bbf 42 165
+17 28 zf 17 20 bbf bbf 40 165
+17 28 zf 17 20 bbf bbf 33 165
+13 25 xf 13 21 ddf ddf 30 52
+13 25 xf 13 21 ddf ddf 22 52
+18 22 tf 18 21 aaf aaf 87 319
+18 22 tf 18 21 aaf aaf 60 319
+18 22 tf 18 21 aaf aaf 25 319
+18 22 tf 18 21 aaf aaf 92 319
+18 22 tf 18 21 aaf aaf 25 319
+18 22 tf 18 21 aaf aaf 30 319
+select *
+from t2, t3, (select c, b, sum(b) over (partition by c) from t4 ) t
+where t2.b < 40 and t2.a=t3.a and t3.c=t.c;
+a b c a b c c b sum(b) over (partition by c)
+7 10 x 7 17 cc cc 12 40
+7 10 x 7 17 cc cc 18 40
+7 10 x 7 17 cc cc 10 40
+7 10 x 7 18 aa aa 77 259
+7 10 x 7 18 aa aa 50 259
+7 10 x 7 18 aa aa 15 259
+7 10 x 7 18 aa aa 82 259
+7 10 x 7 18 aa aa 15 259
+7 10 x 7 18 aa aa 20 259
+7 10 x 7 10 bb bb 40 125
+7 10 x 7 10 bb bb 32 125
+7 10 x 7 10 bb bb 30 125
+7 10 x 7 10 bb bb 23 125
+1 20 a 1 14 bb bb 40 125
+1 20 a 1 14 bb bb 32 125
+1 20 a 1 14 bb bb 30 125
+1 20 a 1 14 bb bb 23 125
+2 23 b 2 12 aa aa 77 259
+2 23 b 2 12 aa aa 50 259
+2 23 b 2 12 aa aa 15 259
+2 23 b 2 12 aa aa 82 259
+2 23 b 2 12 aa aa 15 259
+2 23 b 2 12 aa aa 20 259
+2 23 b 2 11 aa aa 77 259
+2 23 b 2 11 aa aa 50 259
+2 23 b 2 11 aa aa 15 259
+2 23 b 2 11 aa aa 82 259
+2 23 b 2 11 aa aa 15 259
+2 23 b 2 11 aa aa 20 259
+7 18 z 7 17 cc cc 12 40
+7 18 z 7 17 cc cc 18 40
+7 18 z 7 17 cc cc 10 40
+7 18 z 7 18 aa aa 77 259
+7 18 z 7 18 aa aa 50 259
+7 18 z 7 18 aa aa 15 259
+7 18 z 7 18 aa aa 82 259
+7 18 z 7 18 aa aa 15 259
+7 18 z 7 18 aa aa 20 259
+7 18 z 7 10 bb bb 40 125
+7 18 z 7 10 bb bb 32 125
+7 18 z 7 10 bb bb 30 125
+7 18 z 7 10 bb bb 23 125
+1 30 c 1 14 bb bb 40 125
+1 30 c 1 14 bb bb 32 125
+1 30 c 1 14 bb bb 30 125
+1 30 c 1 14 bb bb 23 125
+3 15 x 3 11 dd dd 20 32
+3 15 x 3 11 dd dd 12 32
+8 12 t 8 11 aa aa 77 259
+8 12 t 8 11 aa aa 50 259
+8 12 t 8 11 aa aa 15 259
+8 12 t 8 11 aa aa 82 259
+8 12 t 8 11 aa aa 15 259
+8 12 t 8 11 aa aa 20 259
+11 33 a 11 24 bbf bbf 50 165
+11 33 a 11 24 bbf bbf 42 165
+11 33 a 11 24 bbf bbf 40 165
+11 33 a 11 24 bbf bbf 33 165
+17 10 s 17 27 ccf ccf 22 70
+17 10 s 17 27 ccf ccf 28 70
+17 10 s 17 27 ccf ccf 20 70
+17 10 s 17 28 aaf aaf 87 319
+17 10 s 17 28 aaf aaf 60 319
+17 10 s 17 28 aaf aaf 25 319
+17 10 s 17 28 aaf aaf 92 319
+17 10 s 17 28 aaf aaf 25 319
+17 10 s 17 28 aaf aaf 30 319
+17 10 s 17 20 bbf bbf 50 165
+17 10 s 17 20 bbf bbf 42 165
+17 10 s 17 20 bbf bbf 40 165
+17 10 s 17 20 bbf bbf 33 165
+11 20 v 11 24 bbf bbf 50 165
+11 20 v 11 24 bbf bbf 42 165
+11 20 v 11 24 bbf bbf 40 165
+11 20 v 11 24 bbf bbf 33 165
+12 23 y 12 22 aaf aaf 87 319
+12 23 y 12 22 aaf aaf 60 319
+12 23 y 12 22 aaf aaf 25 319
+12 23 y 12 22 aaf aaf 92 319
+12 23 y 12 22 aaf aaf 25 319
+12 23 y 12 22 aaf aaf 30 319
+12 23 y 12 21 aaf aaf 87 319
+12 23 y 12 21 aaf aaf 60 319
+12 23 y 12 21 aaf aaf 25 319
+12 23 y 12 21 aaf aaf 92 319
+12 23 y 12 21 aaf aaf 25 319
+12 23 y 12 21 aaf aaf 30 319
+17 18 a 17 27 ccf ccf 22 70
+17 18 a 17 27 ccf ccf 28 70
+17 18 a 17 27 ccf ccf 20 70
+17 18 a 17 28 aaf aaf 87 319
+17 18 a 17 28 aaf aaf 60 319
+17 18 a 17 28 aaf aaf 25 319
+17 18 a 17 28 aaf aaf 92 319
+17 18 a 17 28 aaf aaf 25 319
+17 18 a 17 28 aaf aaf 30 319
+17 18 a 17 20 bbf bbf 50 165
+17 18 a 17 20 bbf bbf 42 165
+17 18 a 17 20 bbf bbf 40 165
+17 18 a 17 20 bbf bbf 33 165
+11 30 d 11 24 bbf bbf 50 165
+11 30 d 11 24 bbf bbf 42 165
+11 30 d 11 24 bbf bbf 40 165
+11 30 d 11 24 bbf bbf 33 165
+17 20 xf 17 27 ccf ccf 22 70
+17 20 xf 17 27 ccf ccf 28 70
+17 20 xf 17 27 ccf ccf 20 70
+17 20 xf 17 28 aaf aaf 87 319
+17 20 xf 17 28 aaf aaf 60 319
+17 20 xf 17 28 aaf aaf 25 319
+17 20 xf 17 28 aaf aaf 92 319
+17 20 xf 17 28 aaf aaf 25 319
+17 20 xf 17 28 aaf aaf 30 319
+17 20 xf 17 20 bbf bbf 50 165
+17 20 xf 17 20 bbf bbf 42 165
+17 20 xf 17 20 bbf bbf 40 165
+17 20 xf 17 20 bbf bbf 33 165
+11 30 af 11 24 bbf bbf 50 165
+11 30 af 11 24 bbf bbf 42 165
+11 30 af 11 24 bbf bbf 40 165
+11 30 af 11 24 bbf bbf 33 165
+12 33 bf 12 22 aaf aaf 87 319
+12 33 bf 12 22 aaf aaf 60 319
+12 33 bf 12 22 aaf aaf 25 319
+12 33 bf 12 22 aaf aaf 92 319
+12 33 bf 12 22 aaf aaf 25 319
+12 33 bf 12 22 aaf aaf 30 319
+12 33 bf 12 21 aaf aaf 87 319
+12 33 bf 12 21 aaf aaf 60 319
+12 33 bf 12 21 aaf aaf 25 319
+12 33 bf 12 21 aaf aaf 92 319
+12 33 bf 12 21 aaf aaf 25 319
+12 33 bf 12 21 aaf aaf 30 319
+17 28 zf 17 27 ccf ccf 22 70
+17 28 zf 17 27 ccf ccf 28 70
+17 28 zf 17 27 ccf ccf 20 70
+17 28 zf 17 28 aaf aaf 87 319
+17 28 zf 17 28 aaf aaf 60 319
+17 28 zf 17 28 aaf aaf 25 319
+17 28 zf 17 28 aaf aaf 92 319
+17 28 zf 17 28 aaf aaf 25 319
+17 28 zf 17 28 aaf aaf 30 319
+17 28 zf 17 20 bbf bbf 50 165
+17 28 zf 17 20 bbf bbf 42 165
+17 28 zf 17 20 bbf bbf 40 165
+17 28 zf 17 20 bbf bbf 33 165
+13 25 xf 13 21 ddf ddf 30 52
+13 25 xf 13 21 ddf ddf 22 52
+18 22 tf 18 21 aaf aaf 87 319
+18 22 tf 18 21 aaf aaf 60 319
+18 22 tf 18 21 aaf aaf 25 319
+18 22 tf 18 21 aaf aaf 92 319
+18 22 tf 18 21 aaf aaf 25 319
+18 22 tf 18 21 aaf aaf 30 319
+explain extended select *
+from t2, t3, (select c, b, sum(b) over (partition by c) from t4 ) t
+where t2.b < 40 and t2.a=t3.a and t3.c=t.c;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t2 ALL NULL NULL NULL NULL 90 100.00 Using where
+1 PRIMARY t3 ref idx_a idx_a 5 test.t2.a 2 100.00 Using where
+1 PRIMARY <derived2> ref key0 key0 128 test.t3.c 10 100.00
+2 DERIVED t4 ALL idx_c NULL NULL NULL 160 100.00 Using temporary
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t3`.`c` AS `c`,`t`.`c` AS `c`,`t`.`b` AS `b`,`t`.`sum(b) over (partition by c)` AS `sum(b) over (partition by c)` from `test`.`t2` join `test`.`t3` join (/* select#2 */ select `test`.`t4`.`c` AS `c`,`test`.`t4`.`b` AS `b`,sum(`test`.`t4`.`b`) over ( partition by `test`.`t4`.`c`) AS `sum(b) over (partition by c)` from `test`.`t4`) `t` where `test`.`t3`.`a` = `test`.`t2`.`a` and `t`.`c` = `test`.`t3`.`c` and `test`.`t2`.`b` < 40
+explain format=json select *
+from t2, t3, (select c, b, sum(b) over (partition by c) from t4 ) t
+where t2.b < 40 and t2.a=t3.a and t3.c=t.c;
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "rows": 90,
+ "filtered": 100,
+ "attached_condition": "t2.b < 40 and t2.a is not null"
+ },
+ "table": {
+ "table_name": "t3",
+ "access_type": "ref",
+ "possible_keys": ["idx_a"],
+ "key": "idx_a",
+ "key_length": "5",
+ "used_key_parts": ["a"],
+ "ref": ["test.t2.a"],
+ "rows": 2,
+ "filtered": 100,
+ "attached_condition": "t3.c is not null"
+ },
+ "table": {
+ "table_name": "<derived2>",
+ "access_type": "ref",
+ "possible_keys": ["key0"],
+ "key": "key0",
+ "key_length": "128",
+ "used_key_parts": ["c"],
+ "ref": ["test.t3.c"],
+ "rows": 10,
+ "filtered": 100,
+ "materialized": {
+ "query_block": {
+ "select_id": 2,
+ "window_functions_computation": {
+ "sorts": {
+ "filesort": {
+ "sort_key": "t4.c"
+ }
+ },
+ "temporary_table": {
+ "table": {
+ "table_name": "t4",
+ "access_type": "ALL",
+ "possible_keys": ["idx_c"],
+ "rows": 160,
"filtered": 100
}
}
@@ -13806,39 +14624,53 @@ CREATE TABLE t1 (i int);
INSERT INTO t1 VALUES (1),(9),(3);
CREATE TABLE t2 (a int, i int);
INSERT INTO t2 VALUES (1,9),(2,3),(3,7),(4,1);
-CREATE TABLE t3 (a int, c varchar(8), index(c));
+CREATE TABLE t3 (a int, c char(127), index(c));
INSERT INTO t3 VALUES (1,'foo'),(3,'bar'),(4,'foo'),(2,'bar');
-CREATE TABLE t4 (c varchar(8));
-INSERT INTO t4 VALUES ('abc'),('foo'),('def');
+INSERT INTO t3 SELECT a, concat(c,'a') FROM t3;
+CREATE TABLE t4 (a int, c char(127), index(a));
+INSERT INTO t4 VALUES
+(3,'abc'),(1,'foo'),(4,'def'),(8,'xxx'),(3,'yyy'),
+(5,'zzz'),(9,'xyz'),(2,'yxz'),(5,'zxy'),(7,'zyx') ;
+ANALYZE TABLE t1,t2,t3,t4;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+test.t2 analyze status OK
+test.t3 analyze status OK
+test.t4 analyze status OK
CREATE VIEW v1 AS
SELECT c FROM t3
WHERE a IN ( SELECT t2.a FROM t1 JOIN t2 WHERE t1.i = t2.i ) GROUP BY c ;
-set statement optimizer_switch='split_grouping_derived=off' for SELECT * FROM t4 WHERE c IN ( SELECT c FROM v1 );
-c
-foo
-SELECT * FROM t4 WHERE c IN ( SELECT c FROM v1 );
-c
-foo
-explain extended SELECT * FROM t4 WHERE c IN ( SELECT c FROM v1 );
+set statement optimizer_switch='split_materialized=off' for SELECT * FROM t4 WHERE c IN ( SELECT c FROM v1 ) and a < 2;
+a c
+1 foo
+SELECT * FROM t4 WHERE c IN ( SELECT c FROM v1 ) and a < 2;
+a c
+1 foo
+explain extended SELECT * FROM t4 WHERE c IN ( SELECT c FROM v1 ) and a < 2;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY t4 ALL NULL NULL NULL NULL 3 100.00 Using where
-1 PRIMARY <derived3> ref key0 key0 11 test.t4.c 4 100.00 FirstMatch(t4)
-3 LATERAL DERIVED t3 ALL c NULL NULL NULL 4 75.00 Using where
+1 PRIMARY t4 range a a 5 NULL 1 100.00 Using index condition; Using where
+1 PRIMARY <derived3> ref key0 key0 128 test.t4.c 2 100.00 FirstMatch(t4)
+3 LATERAL DERIVED t3 ref c c 128 test.t4.c 2 100.00
3 LATERAL DERIVED <subquery4> eq_ref distinct_key distinct_key 4 func 1 100.00
4 MATERIALIZED t1 ALL NULL NULL NULL NULL 3 100.00
4 MATERIALIZED t2 ALL NULL NULL NULL NULL 4 100.00 Using where; Using join buffer (flat, BNL join)
Warnings:
-Note 1003 /* select#1 */ select `test`.`t4`.`c` AS `c` from `test`.`t4` semi join (`test`.`v1`) where `v1`.`c` = `test`.`t4`.`c`
-explain format=json SELECT * FROM t4 WHERE c IN ( SELECT c FROM v1 );
+Note 1003 /* select#1 */ select `test`.`t4`.`a` AS `a`,`test`.`t4`.`c` AS `c` from `test`.`t4` semi join (`test`.`v1`) where `v1`.`c` = `test`.`t4`.`c` and `test`.`t4`.`a` < 2
+explain format=json SELECT * FROM t4 WHERE c IN ( SELECT c FROM v1 ) and a < 2;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t4",
- "access_type": "ALL",
- "rows": 3,
+ "access_type": "range",
+ "possible_keys": ["a"],
+ "key": "a",
+ "key_length": "5",
+ "used_key_parts": ["a"],
+ "rows": 1,
"filtered": 100,
+ "index_condition": "t4.a < 2",
"attached_condition": "t4.c is not null"
},
"table": {
@@ -13846,23 +14678,27 @@ EXPLAIN
"access_type": "ref",
"possible_keys": ["key0"],
"key": "key0",
- "key_length": "11",
+ "key_length": "128",
"used_key_parts": ["c"],
"ref": ["test.t4.c"],
- "rows": 4,
+ "rows": 2,
"filtered": 100,
"first_match": "t4",
"materialized": {
"query_block": {
"select_id": 3,
"const_condition": "1",
+ "outer_ref_condition": "t4.c is not null",
"table": {
"table_name": "t3",
- "access_type": "ALL",
+ "access_type": "ref",
"possible_keys": ["c"],
- "rows": 4,
- "filtered": 75,
- "attached_condition": "t3.c = t4.c"
+ "key": "c",
+ "key_length": "128",
+ "used_key_parts": ["c"],
+ "ref": ["test.t4.c"],
+ "rows": 2,
+ "filtered": 100
},
"table": {
"table_name": "<subquery4>",
diff --git a/mysql-test/r/mysqld--help.result b/mysql-test/r/mysqld--help.result
index cb538a352bc..0e9a0d3dc5d 100644
--- a/mysql-test/r/mysqld--help.result
+++ b/mysql-test/r/mysqld--help.result
@@ -665,7 +665,7 @@ The following options may be given as the first argument:
join_cache_hashed, join_cache_bka,
optimize_join_buffer_size, table_elimination,
extended_keys, exists_to_in, orderby_uses_equalities,
- condition_pushdown_for_derived, split_grouping_derived
+ condition_pushdown_for_derived, split_materialized
--optimizer-use-condition-selectivity=#
Controls selectivity of which conditions the optimizer
takes into account to calculate cardinality of a partial
@@ -1510,7 +1510,7 @@ old-style-user-limits FALSE
optimizer-prune-level 1
optimizer-search-depth 62
optimizer-selectivity-sampling-limit 100
-optimizer-switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_grouping_derived=on
+optimizer-switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
optimizer-use-condition-selectivity 1
performance-schema FALSE
performance-schema-accounts-size -1
diff --git a/mysql-test/r/selectivity.result b/mysql-test/r/selectivity.result
index cdb210ae2d9..9cb6ee3e9bf 100644
--- a/mysql-test/r/selectivity.result
+++ b/mysql-test/r/selectivity.result
@@ -141,7 +141,7 @@ order by s_suppkey;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY supplier ALL PRIMARY NULL NULL NULL 10 100.00 Using filesort
1 PRIMARY <derived3> ref key0 key0 5 dbt3_s001.supplier.s_suppkey 10 100.00 Using where
-3 LATERAL DERIVED lineitem range i_l_shipdate,i_l_suppkey i_l_shipdate 4 NULL 268 75.00 Using where
+3 DERIVED lineitem range i_l_shipdate,i_l_suppkey i_l_shipdate 4 NULL 268 100.00 Using where; Using temporary; Using filesort
2 SUBQUERY <derived4> ALL NULL NULL NULL NULL 268 100.00
4 DERIVED lineitem range i_l_shipdate i_l_shipdate 4 NULL 268 100.00 Using where; Using temporary; Using filesort
Warnings:
@@ -162,7 +162,7 @@ order by s_suppkey;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY supplier ALL PRIMARY NULL NULL NULL 10 100.00 Using filesort
1 PRIMARY <derived3> ref key0 key0 5 dbt3_s001.supplier.s_suppkey 10 100.00 Using where
-3 LATERAL DERIVED lineitem range i_l_shipdate,i_l_suppkey i_l_shipdate 4 NULL 268 100.00 Using where
+3 DERIVED lineitem range i_l_shipdate,i_l_suppkey i_l_shipdate 4 NULL 268 100.00 Using where; Using temporary; Using filesort
2 SUBQUERY <derived4> ALL NULL NULL NULL NULL 268 100.00
4 DERIVED lineitem range i_l_shipdate i_l_shipdate 4 NULL 268 100.00 Using where; Using temporary; Using filesort
Warnings:
diff --git a/mysql-test/r/selectivity_innodb.result b/mysql-test/r/selectivity_innodb.result
index 47d2e6fd554..236647c6091 100644
--- a/mysql-test/r/selectivity_innodb.result
+++ b/mysql-test/r/selectivity_innodb.result
@@ -144,7 +144,7 @@ order by s_suppkey;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY supplier index PRIMARY PRIMARY 4 NULL 10 100.00
1 PRIMARY <derived3> ref key0 key0 5 dbt3_s001.supplier.s_suppkey 10 100.00 Using where
-3 LATERAL DERIVED lineitem range i_l_shipdate,i_l_suppkey i_l_shipdate 4 NULL 229 75.11 Using where
+3 DERIVED lineitem range i_l_shipdate,i_l_suppkey i_l_shipdate 4 NULL 229 100.00 Using where; Using temporary; Using filesort
2 SUBQUERY <derived4> ALL NULL NULL NULL NULL 229 100.00
4 DERIVED lineitem range i_l_shipdate i_l_shipdate 4 NULL 229 100.00 Using where; Using temporary; Using filesort
Warnings:
@@ -165,7 +165,7 @@ order by s_suppkey;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY supplier index PRIMARY PRIMARY 4 NULL 10 100.00
1 PRIMARY <derived3> ref key0 key0 5 dbt3_s001.supplier.s_suppkey 10 100.00 Using where
-3 LATERAL DERIVED lineitem range i_l_shipdate,i_l_suppkey i_l_shipdate 4 NULL 229 100.00 Using where
+3 DERIVED lineitem range i_l_shipdate,i_l_suppkey i_l_shipdate 4 NULL 229 100.00 Using where; Using temporary; Using filesort
2 SUBQUERY <derived4> ALL NULL NULL NULL NULL 228 100.00
4 DERIVED lineitem range i_l_shipdate i_l_shipdate 4 NULL 229 100.00 Using where; Using temporary; Using filesort
Warnings:
diff --git a/mysql-test/suite/sys_vars/r/optimizer_switch_basic.result b/mysql-test/suite/sys_vars/r/optimizer_switch_basic.result
index cb3291dadea..87c837986ac 100644
--- a/mysql-test/suite/sys_vars/r/optimizer_switch_basic.result
+++ b/mysql-test/suite/sys_vars/r/optimizer_switch_basic.result
@@ -1,63 +1,63 @@
SET @start_global_value = @@global.optimizer_switch;
SELECT @start_global_value;
@start_global_value
-index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_grouping_derived=on
+index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
select @@global.optimizer_switch;
@@global.optimizer_switch
-index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_grouping_derived=on
+index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
select @@session.optimizer_switch;
@@session.optimizer_switch
-index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_grouping_derived=on
+index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
show global variables like 'optimizer_switch';
Variable_name Value
-optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_grouping_derived=on
+optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
show session variables like 'optimizer_switch';
Variable_name Value
-optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_grouping_derived=on
+optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
select * from information_schema.global_variables where variable_name='optimizer_switch';
VARIABLE_NAME VARIABLE_VALUE
-OPTIMIZER_SWITCH index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_grouping_derived=on
+OPTIMIZER_SWITCH index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
select * from information_schema.session_variables where variable_name='optimizer_switch';
VARIABLE_NAME VARIABLE_VALUE
-OPTIMIZER_SWITCH index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_grouping_derived=on
+OPTIMIZER_SWITCH index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
set global optimizer_switch=10;
set session optimizer_switch=5;
select @@global.optimizer_switch;
@@global.optimizer_switch
-index_merge=off,index_merge_union=on,index_merge_sort_union=off,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_grouping_derived=off
+index_merge=off,index_merge_union=on,index_merge_sort_union=off,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off
select @@session.optimizer_switch;
@@session.optimizer_switch
-index_merge=on,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_grouping_derived=off
+index_merge=on,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off
set global optimizer_switch="index_merge_sort_union=on";
set session optimizer_switch="index_merge=off";
select @@global.optimizer_switch;
@@global.optimizer_switch
-index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_grouping_derived=off
+index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off
select @@session.optimizer_switch;
@@session.optimizer_switch
-index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_grouping_derived=off
+index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off
show global variables like 'optimizer_switch';
Variable_name Value
-optimizer_switch index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_grouping_derived=off
+optimizer_switch index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off
show session variables like 'optimizer_switch';
Variable_name Value
-optimizer_switch index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_grouping_derived=off
+optimizer_switch index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off
select * from information_schema.global_variables where variable_name='optimizer_switch';
VARIABLE_NAME VARIABLE_VALUE
-OPTIMIZER_SWITCH index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_grouping_derived=off
+OPTIMIZER_SWITCH index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off
select * from information_schema.session_variables where variable_name='optimizer_switch';
VARIABLE_NAME VARIABLE_VALUE
-OPTIMIZER_SWITCH index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_grouping_derived=off
+OPTIMIZER_SWITCH index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off
set session optimizer_switch="default";
select @@session.optimizer_switch;
@@session.optimizer_switch
-index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_grouping_derived=off
+index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off
set optimizer_switch = replace(@@optimizer_switch, '=off', '=on');
Warnings:
Warning 1681 'engine_condition_pushdown=on' is deprecated and will be removed in a future release
select @@optimizer_switch;
@@optimizer_switch
-index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=on,mrr_cost_based=on,mrr_sort_keys=on,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_grouping_derived=on
+index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=on,mrr_cost_based=on,mrr_sort_keys=on,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
set global optimizer_switch=1.1;
ERROR 42000: Incorrect argument type to variable 'optimizer_switch'
set global optimizer_switch=1e1;
@@ -69,4 +69,4 @@ ERROR 42000: Variable 'optimizer_switch' can't be set to the value of 'foobar'
SET @@global.optimizer_switch = @start_global_value;
SELECT @@global.optimizer_switch;
@@global.optimizer_switch
-index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_grouping_derived=on
+index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result
index 3ba61fa8915..d087df07278 100644
--- a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result
+++ b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result
@@ -8,6 +8,7 @@ where variable_name not like 'aria%' and
variable_name not like 'debug%' and
variable_name not like 'wsrep%' and
variable_name not in (
+'in_predicate_conversion_threshold',
'have_openssl',
'have_symlink',
'hostname',
@@ -2672,17 +2673,17 @@ ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME OPTIMIZER_SWITCH
-SESSION_VALUE index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_grouping_derived=on
-GLOBAL_VALUE index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_grouping_derived=on
+SESSION_VALUE index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
+GLOBAL_VALUE index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
GLOBAL_VALUE_ORIGIN COMPILE-TIME
-DEFAULT_VALUE index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_grouping_derived=on
+DEFAULT_VALUE index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
VARIABLE_SCOPE SESSION
VARIABLE_TYPE FLAGSET
VARIABLE_COMMENT Fine-tune the optimizer behavior
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
-ENUM_VALUE_LIST index_merge,index_merge_union,index_merge_sort_union,index_merge_intersection,index_merge_sort_intersection,engine_condition_pushdown,index_condition_pushdown,derived_merge,derived_with_keys,firstmatch,loosescan,materialization,in_to_exists,semijoin,partial_match_rowid_merge,partial_match_table_scan,subquery_cache,mrr,mrr_cost_based,mrr_sort_keys,outer_join_with_cache,semijoin_with_cache,join_cache_incremental,join_cache_hashed,join_cache_bka,optimize_join_buffer_size,table_elimination,extended_keys,exists_to_in,orderby_uses_equalities,condition_pushdown_for_derived,split_grouping_derived,default
+ENUM_VALUE_LIST index_merge,index_merge_union,index_merge_sort_union,index_merge_intersection,index_merge_sort_intersection,engine_condition_pushdown,index_condition_pushdown,derived_merge,derived_with_keys,firstmatch,loosescan,materialization,in_to_exists,semijoin,partial_match_rowid_merge,partial_match_table_scan,subquery_cache,mrr,mrr_cost_based,mrr_sort_keys,outer_join_with_cache,semijoin_with_cache,join_cache_incremental,join_cache_hashed,join_cache_bka,optimize_join_buffer_size,table_elimination,extended_keys,exists_to_in,orderby_uses_equalities,condition_pushdown_for_derived,split_materialized,default
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME OPTIMIZER_USE_CONDITION_SELECTIVITY
diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result
index 4f5a08211f5..8b1ce78f960 100644
--- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result
+++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result
@@ -2883,17 +2883,17 @@ ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME OPTIMIZER_SWITCH
-SESSION_VALUE index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_grouping_derived=on
-GLOBAL_VALUE index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_grouping_derived=on
+SESSION_VALUE index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
+GLOBAL_VALUE index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
GLOBAL_VALUE_ORIGIN COMPILE-TIME
-DEFAULT_VALUE index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_grouping_derived=on
+DEFAULT_VALUE index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
VARIABLE_SCOPE SESSION
VARIABLE_TYPE FLAGSET
VARIABLE_COMMENT Fine-tune the optimizer behavior
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
-ENUM_VALUE_LIST index_merge,index_merge_union,index_merge_sort_union,index_merge_intersection,index_merge_sort_intersection,engine_condition_pushdown,index_condition_pushdown,derived_merge,derived_with_keys,firstmatch,loosescan,materialization,in_to_exists,semijoin,partial_match_rowid_merge,partial_match_table_scan,subquery_cache,mrr,mrr_cost_based,mrr_sort_keys,outer_join_with_cache,semijoin_with_cache,join_cache_incremental,join_cache_hashed,join_cache_bka,optimize_join_buffer_size,table_elimination,extended_keys,exists_to_in,orderby_uses_equalities,condition_pushdown_for_derived,split_grouping_derived,default
+ENUM_VALUE_LIST index_merge,index_merge_union,index_merge_sort_union,index_merge_intersection,index_merge_sort_intersection,engine_condition_pushdown,index_condition_pushdown,derived_merge,derived_with_keys,firstmatch,loosescan,materialization,in_to_exists,semijoin,partial_match_rowid_merge,partial_match_table_scan,subquery_cache,mrr,mrr_cost_based,mrr_sort_keys,outer_join_with_cache,semijoin_with_cache,join_cache_incremental,join_cache_hashed,join_cache_bka,optimize_join_buffer_size,table_elimination,extended_keys,exists_to_in,orderby_uses_equalities,condition_pushdown_for_derived,split_materialized,default
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME OPTIMIZER_USE_CONDITION_SELECTIVITY
diff --git a/mysql-test/t/derived_cond_pushdown.test b/mysql-test/t/derived_cond_pushdown.test
index 2a3da09a3d7..787c3032f53 100644
--- a/mysql-test/t/derived_cond_pushdown.test
+++ b/mysql-test/t/derived_cond_pushdown.test
@@ -2145,7 +2145,7 @@ drop table t1;
--echo #
set @save_optimizer_switch= @@optimizer_switch;
-set optimizer_switch='split_grouping_derived=off';
+set optimizer_switch='split_materialized=off';
create table t1 (a int, c varchar(16));
insert into t1 values
@@ -2256,28 +2256,62 @@ set optimizer_switch= @save_optimizer_switch;
--echo #
let
-$no_splitting= set statement optimizer_switch='split_grouping_derived=off' for;
+$no_splitting= set statement optimizer_switch='split_materialized=off' for;
-create table t1 (a int);
+create table t1 (a int, b int, index idx_b(b)) engine=myisam;
insert into t1 values
-(8), (5), (1), (2), (9), (7), (2), (7);
+(8,3), (5,7), (1,2), (2,1), (9,7), (7,5), (2,2), (7,3),
+(9,3), (8,1), (4,5), (2,3);
-create table t2 (a int, b int, index idx(a));
+create table t2 (a int, b int, c char(127), index idx_a(a)) engine=myisam;
insert into t2 values
- (7,10), (1,20), (2,23), (7,18), (1,30),
- (4,71), (3,15), (7,82), (8,12), (4,15),
- (11,33), (10,42), (4,53), (10,17), (2,90);
+ (7,10,'x'), (1,20,'a'), (2,23,'b'), (7,18,'z'), (1,30,'c'),
+ (4,71,'d'), (3,15,'x'), (7,82,'y'), (8,12,'t'), (4,15,'b'),
+ (11,33,'a'), (10,42,'u'), (4,53,'p'), (10,17,'r'), (2,90,'x'),
+ (17,10,'s'), (11,20,'v'), (12,23,'y'), (17,18,'a'), (11,30,'d'),
+ (24,71,'h'), (23,15,'i'), (27,82,'k'), (28,12,'p'), (24,15,'q'),
+ (31,33,'f'), (30,42,'h'), (40,53,'m'), (30,17,'o'), (21,90,'b'),
+ (37,10,'e'), (31,20,'g'), (32,23,'f'), (37,18,'n'), (41,30,'l'),
+ (54,71,'j'), (53,15,'w'), (57,82,'z'), (58,12,'k'), (54,15,'p'),
+ (61,33,'c'), (60,42,'a'), (62,53,'x'), (67,17,'g'), (64,90,'v');
+
+insert into t2 select a+10, b+10, concat(c,'f') from t2;
+
+analyze table t1,t2;
let $q1=
-select t1.a,t.max,t.min
+select t1.a,t.s,t.m
from t1 join
- (select a, max(t2.b) max, min(t2.b) min from t2 group by t2.a) t
- on t1.a=t.a;
+ (select a, sum(t2.b) as s, min(t2.c) as m from t2 group by t2.a) t
+ on t1.a=t.a
+where t1.b < 3;
eval $no_splitting $q1;
eval $q1;
eval explain extended $q1;
-eval explain format=json $q1;
+eval explain format=json $q1;
+eval prepare stmt from "$q1";
+execute stmt;
+execute stmt;
+deallocate prepare stmt;
+
+let $q10=
+select t1.a,t.s,t.m
+from t1 join
+ (select a, sum(t2.b) as s, min(t2.b) as m from t2 group by t2.a) t
+ on t1.a=t.a
+where t1.b <= 5;
+
+eval $no_splitting $q10;
+eval $q10;
+eval explain extended $q10;
+eval explain format=json $q10;
+eval prepare stmt from "$q10";
+execute stmt;
+execute stmt;
+deallocate prepare stmt;
+
+delete from t1 where t1.b between 2 and 5;
let $q2=
select t1.a,t.max,t.min
@@ -2290,68 +2324,122 @@ eval $q2;
eval explain extended $q2;
eval explain format=json $q2;
-create table t3 (a int, c varchar(16));
+create table t3 (a int, b int, c char(127), index idx_b(b)) engine=myisam;
insert into t3 values
-(8,'aa'), (5,'cc'), (1,'bb'), (2,'aa'), (9,'cc'),
-(7,'aa'), (2,'aa'), (7,'bb');
+(8,11,'aa'), (5,15,'cc'), (1,14,'bb'), (2,12,'aa'), (7,17,'cc'),
+(7,18,'aa'), (2,11,'aa'), (7,10,'bb'), (3,11,'dd'), (4,12,'ee'),
+(5,14,'dd'), (9,12,'ee');
-create table t4 (a int, b int, c varchar(16), index idx(a,c));
+create table t4 (a int, b int, c char(127), index idx(a,c)) engine=myisam;
insert into t4 values
(7,10,'cc'), (1,20,'aa'), (2,23,'bb'), (7,18,'cc'), (1,30,'bb'),
- (4,71,'xx'), (3,15,'aa'), (7,82,'bb'), (8,12,'dd'), (4,15,'aa'),
- (11,33,'yy'), (10,42,'zz'), (4,53,'xx'), (10,17,'yy'), (7,12,'bb'),
+ (4,71,'xx'), (3,15,'aa'), (7,82,'aa'), (8,12,'dd'), (4,15,'aa'),
+ (11,33,'yy'), (10,42,'zz'), (4,53,'xx'), (10,17,'yy'), (7,12,'cc'),
(8,20,'dd'), (7,32,'bb'), (1,50,'aa'), (3,40,'bb'), (3,77,'aa');
+insert into t4 select a+10, b+10, concat(c,'f') from t4;
+
+analyze table t3,t4;
+
let $q3=
select t3.a,t3.c,t.max,t.min
from t3 join
(select a, c, max(b) max, min(b) min from t4 group by a,c) t
- on t3.a=t.a and t3.c=t.c;
+ on t3.a=t.a and t3.c=t.c
+where t3.b > 15;
eval $no_splitting $q3;
eval $q3;
eval explain extended $q3;
eval explain format=json $q3;
+let $q30=
+select t3.a,t3.c,t.max,t.min
+from t3 join
+ (select a, c, max(b) max, min(b) min from t4 group by a,c) t
+ on t3.a=t.a and t3.c=t.c
+where t3.b <= 15;
+
+eval $no_splitting $q30;
+eval $q30;
+eval explain extended $q30;
+eval explain format=json $q30;
+
let $q4=
select t3.a,t3.c,t.max,t.min
from t3 join
(select a, c, max(b) max, min(b) min from t4 group by c,a) t
- on t3.a=t.a and t3.c=t.c;
+ on t3.a=t.a and t3.c=t.c
+where t3.b > 15;
eval $no_splitting $q4;
eval $q4;
eval explain extended $q4;
eval explain format=json $q4;
-drop index idx on t2;
-create index idx on t2(b);
-create index idx on t3(a);
-create index idx2 on t4(c);
-insert into t3 select a+1, concat(c,'f') from t3;
-insert into t3 select a+1, concat(c,'h') from t3;
-insert into t4 select a+1, b+10, concat(c,'h') from t4;
+let $q40=
+select t3.a,t3.c,t.max,t.min
+from t3 join
+ (select a, c, max(b) max, min(b) min from t4 group by c,a) t
+ on t3.a=t.a and t3.c=t.c
+where t3.b <= 15;
+
+eval $no_splitting $q40;
+eval $q40;
+eval explain extended $q40;
+eval explain format=json $q40;
+
+drop index idx_a on t2;
+create index idx on t2(c,b);
+create index idx_a on t3(a);
+create index idx_c on t4(c);
+insert into t3 select a+10, b+10, concat(c,'f') from t3;
+insert into t3 select a+100, b+100, concat(c,'g') from t3;
+insert into t4 select a+100, b+100, concat(c,'g') from t4;
+insert into t4 select a+1000, b+1000, concat(c,'h') from t4;
+
+analyze table t2,t3,t4;
let $q5=
-select t2.a,t2.b,t3.c,t.max,t.min
+select t2.a,t2.b,t2.c,t.c as t_c,t.max,t.min
from t2, t3, (select c, max(b) max, min(b) min from t4 group by c) t
-where t2.b > 50 and t2.a=t3.a and t3.c=t.c;
+where t2.b between 80 and 85 and t2.c in ('y','z') and t2.a=t3.a and t3.c=t.c;
eval $no_splitting $q5;
eval $q5;
eval explain extended $q5;
eval explain format=json $q5;
+let $q50=
+select t2.a,t2.b,t2.c,t.c as t_c,t.max,t.min
+from t2, t3, (select c, max(b) max, min(b) min from t4 group by c) t
+where t2.b < 40 and t2.a=t3.a and t3.c=t.c;
+
+eval $no_splitting $q50;
+eval $q50;
+eval explain extended $q50;
+eval explain format=json $q50;
+
let $q6=
select *
from t2, t3, (select c, b, sum(b) over (partition by c) from t4 ) t
-where t2.b > 50 and t2.a=t3.a and t3.c=t.c;
+where t2.b between 80 and 85 and t2.c in ('y','z') and t2.a=t3.a and t3.c=t.c;
eval $no_splitting $q6;
eval $q6;
eval explain extended $q6;
eval explain format=json $q6;
+let $q60=
+select *
+from t2, t3, (select c, b, sum(b) over (partition by c) from t4 ) t
+where t2.b < 40 and t2.a=t3.a and t3.c=t.c;
+
+eval $no_splitting $q60;
+eval $q60;
+eval explain extended $q60;
+eval explain format=json $q60;
+
drop table t1,t2,t3,t4;
--echo #
@@ -2365,18 +2453,23 @@ INSERT INTO t1 VALUES (1),(9),(3);
CREATE TABLE t2 (a int, i int);
INSERT INTO t2 VALUES (1,9),(2,3),(3,7),(4,1);
-CREATE TABLE t3 (a int, c varchar(8), index(c));
+CREATE TABLE t3 (a int, c char(127), index(c));
INSERT INTO t3 VALUES (1,'foo'),(3,'bar'),(4,'foo'),(2,'bar');
+INSERT INTO t3 SELECT a, concat(c,'a') FROM t3;
+
+CREATE TABLE t4 (a int, c char(127), index(a));
+INSERT INTO t4 VALUES
+ (3,'abc'),(1,'foo'),(4,'def'),(8,'xxx'),(3,'yyy'),
+ (5,'zzz'),(9,'xyz'),(2,'yxz'),(5,'zxy'),(7,'zyx') ;
-CREATE TABLE t4 (c varchar(8));
-INSERT INTO t4 VALUES ('abc'),('foo'),('def');
+ANALYZE TABLE t1,t2,t3,t4;
CREATE VIEW v1 AS
SELECT c FROM t3
WHERE a IN ( SELECT t2.a FROM t1 JOIN t2 WHERE t1.i = t2.i ) GROUP BY c ;
let $q1=
-SELECT * FROM t4 WHERE c IN ( SELECT c FROM v1 );
+SELECT * FROM t4 WHERE c IN ( SELECT c FROM v1 ) and a < 2;
eval $no_splitting $q1;
eval $q1;
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index 24e1dd27d02..9f796896a41 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -145,6 +145,7 @@ SET (SQL_SOURCE
sql_cte.cc
sql_sequence.cc sql_sequence.h ha_sequence.h
sql_tvc.cc sql_tvc.h
+ opt_split.cc
${WSREP_SOURCES}
table_cache.cc encryption.cc temporary_tables.cc
proxy_protocol.cc
diff --git a/sql/opt_split.cc b/sql/opt_split.cc
new file mode 100644
index 00000000000..786ed7a27c3
--- /dev/null
+++ b/sql/opt_split.cc
@@ -0,0 +1,1132 @@
+/*
+ Copyright (c) 2017 MariaDB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+/*
+ This file contains functions to support the splitting technique.
+ This optimization technique can be applied to equi-joins involving
+ materialized tables such as materialized views, materialized derived tables
+ and materialized CTEs. The technique also could be applied to materialized
+ semi-joins though the code below does not support this usage yet.
+
+ Here are the main ideas behind this technique that we'll call SM optimization
+ (SplitMaterialization).
+
+ Consider the query
+ SELECT t1.a, t.min
+ FROM t1, (SELECT t2.a, MIN(t2.b) as min FROM t2 GROUP BY t2.a) t
+ WHERE t1.a = t.a and t1.b < const
+
+ Re-write the query into
+ SELECT t1.a, t.min
+ FROM t1, LATERAL (SELECT t2.a, MIN(t2.b) as min
+ FROM t2 WHERE t2.a = t1.a GROUP BY t2.a) t
+ WHERE t1.b < const
+
+ The execution of the original query (Q1) does the following:
+ 1. Executes the query in the specification of the derived table
+ and puts the result set into a temporary table with an index
+ on the first column.
+ 2. Joins t1 with the temporary table using the its index.
+
+ The execution of the transformed query (Q1R) follows these steps:
+ 1. For each row of t1 where t1.b < const a temporary table
+ containing all rows of of t2 with t2.a = t1.a is created
+ 2. If there are any rows in the temporary table aggregation
+ is performed for them
+ 3. The result of the aggregation is joined with t1.
+
+ The second execution can win if:
+ a) There is an efficient way to select rows of t2 for which t2.a = t1.a
+ (For example if there is an index on t2.a)
+ and
+ b) The number of temporary tables created for partitions
+ is much smaller that the total number of partitions
+
+ It should be noted that for the transformed query aggregation
+ for a partition may be performed several times.
+
+ As we can see the optimization basically splits table t2 into
+ partitions and performs aggregation over each of them
+ independently.
+
+ If we have only one equi-join condition then we either push it as
+ for Q1R or we don't. In a general case we may have much more options.
+ Consider the query (Q3)
+ SELECT
+ FROM t1,t2 (SELECT t3.a, t3.b, MIN(t3.c) as min
+ FROM t3 GROUP BY a,b) t
+ WHERE t.a = t1.a AND t.b = t2.b
+ AND t1.c < c1 and t2.c < c2
+ AND P(t1,t2);
+ (P(t1,t2) designates some additional conditions over columns of t1,t2).
+
+ Assuming that there indexes on t3(a,b) and t3(b) here we have several
+ reasonable options to push equi-join conditions into the derived.
+ All these options should be taken into account when the optimizer
+ evaluates different join orders. When the join order (t1,t,t2) is
+ evaluated there is only one way of splitting : to push the condition
+ t.a = t1.a into t. With the join order (t2,t,t1) only the condition
+ t.b = t2.b can be pushed. When the join orders (t1,t2,t) and (t2,t1,t)
+ are evaluated then the optimizer should consider pushing t.a = t1.a,
+ t.b = t2.b and (t.a = t1.a AND t.b = t2.b) to choose the best condition
+ for splitting. Apparently here last condition is the best one because
+ it provides the miximum possible number of partitions.
+
+ If we dropped the index on t3(a,b) and created the index on t3(a) instead
+ then we would have two options for splitting: to push t.a = t1.a or to
+ push t.b = t2.b. If the selectivity of the index t3(a) is better than
+ the selectivity of t3(b) then the first option is preferred.
+
+ Although the condition (t.a = t1.a AND t.b = t2.b) provides a better
+ splitting than the condition t.a = t1.a the latter will be used for
+ splitting if the execution plan with the join order (t1,t,t2) turns out
+ to be the cheapest one. It's quite possible when the join condition
+ P(t1,t2) has a bad selectivity.
+
+ Whenever the optimizer evaluates the cost of using a splitting it
+ compares it with the cost of materialization without splitting.
+
+ If we just drop the index on t3(a,b) the chances that the splitting
+ will be used becomes much lower but they still exists providing that
+ the fanout of the partial join of t1 and t2 is small enough.
+*/
+
+/*
+ Splitting can be applied to a materialized table specified by the query
+ with post-join operations that require partitioning of the result set produced
+ by the join expression used in the FROM clause the query such as GROUP BY
+ operation and window function operation. In any of these cases the post-join
+ operation can be executed independently for any partition only over the rows
+ of this partition. Also if the set of all partitions is divided into disjoint
+ subsets the operation can applied to each subset independently. In this case
+ all rows are first partitioned into the groups each of which contains all the
+ rows from the partitions belonging the same subset and then each group
+ is subpartitioned into groups in the the post join operation.
+
+ The set of all rows belonging to the union of several partitions is called
+ here superpartition. If a grouping operation is defined by the list
+ e_1,...,e_n then any set S = {e_i1,...,e_ik} can be used to devide all rows
+ into superpartions such that for any two rows r1, r2 the following holds:
+ e_ij(r1) = e_ij(r2) for each e_ij from S. We use the splitting technique
+ only if S consists of references to colums of the joined tables.
+ For example if the GROUP BY list looks like this a, g(b), c we can consider
+ applying the splitting technique to the superpartitions defined by {a,c},
+ {a}, {c} (a and c here may be the references to the columns from different
+ tables).
+*/
+
+ /*
+ The following describes when and how the optimizer decides whether it
+ makes sense to employ the splitting technique.
+
+ 1. For each instance of a materialized table (derived/view/CTE) it is
+ checked that it is potentially splittable. Now it is done right after the
+ execution plan for the select specifying this table has been chosen.
+
+ 2. Any potentially splittable materialized table T is subject to two-phase
+ optimization. It means that the optimizer first builds the best execution
+ plan for join that specifies T. Then the control is passed back to the
+ optimization process of the embedding select Q. After the execution plan
+ for Q has been chosen the optimizer finishes the optimization of the join
+ specifying T.
+
+ 3. When the optimizer builds the container with the KEYUSE structures
+ for the join of embedding select it detects the equi-join conditions
+ PC that potentially could be pushed into a potentially splittable
+ materialized table T. The collected information about such conditions
+ is stored together with other facts on potential splittings for table T.
+
+ 4. When the optimizer starts looking for the best execution plan for the
+ embedding select Q for each potentially splittable materialized table T
+ it creates special KEYUSE structures for pushable equi-join conditions
+ PC. These structures are used to add new elements to the container
+ of KEYUSE structures built for T. The specifics of these elements is
+ that they can be ebabled and disabled during the process of choosing
+ the best plan for Q.
+
+ 5. When the optimizer extends a partial join order with a potentially
+ splittable materialized table T (in function best_access_path) it
+ first evaluates a new execution plan for the modified specification
+ of T that adds all equi-join conditions that can be pushed with
+ current join prefix to the WHERE conditions of the original
+ specification of T. If the cost of the new plan is better than the
+ the cost of the original materialized table then the optimizer
+ prefers to use splitting for the current join prefix. As the cost
+ of the plan depends only on the pushed conditions it makes sense
+ to cache this plan for other prefixes.
+
+ 6. The optimizer takes into account the cost of splitting / materialization
+ of a potentially splittable materialized table T as a startup cost
+ to access table T.
+
+ 7. When the optimizer finally chooses the best execution plan for
+ the embedding select Q and this plan prefers using splitting
+ for table T with pushed equi-join conditions PC then the execution
+ plan for the underlying join with these conditions is chosen for T.
+*/
+
+/*
+ The implementation of the splitting technique below allows to apply
+ the technique only to a materialized derived table / view / CTE whose
+ specification is either a select with GROUP BY or a non-grouping select
+ with window functions that share the same PARTITION BY list.
+*/
+
+#include "mariadb.h"
+#include "sql_select.h"
+
+/* Info on a splitting field */
+struct SplM_field_info
+{
+ /* Splitting field in the materialized table T */
+ Field *mat_field;
+ /* The item from the select list of the specification of T */
+ Item *producing_item;
+ /* The corresponding splitting field from the specification of T */
+ Field *underlying_field;
+};
+
+
+/* Info on the splitting execution plan saved in SplM_opt_info::cache */
+struct SplM_plan_info
+{
+ /* The cached splitting execution plan P */
+ struct st_position *best_positions;
+ /* The cost of the above plan */
+ double cost;
+ /* Selectivity of splitting used in P */
+ double split_sel;
+ /* For fast search of KEYUSE_EXT elements used for splitting in P */
+ struct KEYUSE_EXT *keyuse_ext_start;
+ /* The tables that contains the fields used for splitting in P */
+ TABLE *table;
+ /* The number of the key from 'table' used for splitting in P */
+ uint key;
+ /* Number of the components of 'key' used for splitting in P */
+ uint parts;
+};
+
+
+/*
+ The structure contains the information that is used by the optimizer
+ for potentially splittable materialization of T that is a materialized
+ derived_table / view / CTE
+*/
+class SplM_opt_info : public Sql_alloc
+{
+public:
+ /* The join for the select specifying T */
+ JOIN *join;
+ /* The map of tables from 'join' whose columns can be used for partitioning */
+ table_map tables_usable_for_splitting;
+ /* Info about the fields of the joined tables usable for splitting */
+ SplM_field_info *spl_fields;
+ /* The number of elements in the above list */
+ uint spl_field_cnt;
+ /* Contains the structures to generate all KEYUSEs for pushable equalities */
+ List<KEY_FIELD> added_key_fields;
+ /* The cache of evaluated execution plans for 'join' with pushed equalities */
+ List<SplM_plan_info> plan_cache;
+ /* Cost of best execution plan for join when nothing is pushed */
+ double unsplit_cost;
+ /* Cardinality of T when nothing is pushed */
+ double unsplit_card;
+ /* Lastly evaluated execution plan for 'join' with pushed equalities */
+ SplM_plan_info *last_plan;
+
+ SplM_plan_info *find_plan(TABLE *table, uint key, uint parts);
+};
+
+
+void TABLE::set_spl_opt_info(SplM_opt_info *spl_info)
+{
+ if (spl_info)
+ spl_info->join->spl_opt_info= spl_info;
+ spl_opt_info= spl_info;
+}
+
+
+void TABLE::deny_splitting()
+{
+ DBUG_ASSERT(spl_opt_info != NULL);
+ spl_opt_info->join->spl_opt_info= NULL;
+ spl_opt_info= NULL;
+}
+
+
+/* This structure is auxiliary and used only in the function that follows it */
+struct SplM_field_ext_info: public SplM_field_info
+{
+ uint item_no;
+ bool is_usable_for_ref_access;
+};
+
+
+/**
+ @brief
+ Check whether this join is one for potentially splittable materialized table
+
+ @details
+ The function checks whether this join is for select that specifies
+ a potentially splittable materialized table T. If so, the collected
+ info on potential splittability of T is attached to the field spl_opt_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'
+ 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
+ 5. T is not recursive
+ 6. T is either
+ 6.1. a grouping table with GROUP BY list P
+ or
+ 6.2. a non-grouping table with window functions over the same non-empty
+ partition specified by the PARTITION BY list P
+ 7. P contains some references on the columns of the joined tables C
+ occurred also in the select list of this join
+ 8. There are defined some keys usable for ref access of fields from C
+ with available statistics.
+
+ @retval
+ true if the answer is positive
+ false otherwise
+*/
+
+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)
+ (unit->first_select()->next_select()) || // !(3)
+ (derived->prohibit_cond_pushdown) || // !(4)
+ (derived->is_recursive_with_table())) // !(5)
+ return false;
+ if (group_list) // (6.1)
+ {
+ if (!select_lex->have_window_funcs())
+ partition_list= group_list;
+ }
+ else if (select_lex->have_window_funcs() &&
+ select_lex->window_specs.elements == 1) // (6.2)
+ {
+ partition_list=
+ select_lex->window_specs.head()->partition_list->first;
+ }
+ if (!partition_list)
+ return false;
+
+ ORDER *ord;
+ Dynamic_array<SplM_field_ext_info> candidates;
+
+ /*
+ Select from partition_list all candidates for splitting.
+ A candidate must be
+ - field item or refer to such (7.1)
+ - item mentioned in the select list (7.2)
+ Put info about such candidates into the array candidates
+ */
+ table_map usable_tables= 0; // tables that contains the candidate
+ for (ord= partition_list; ord; ord= ord->next)
+ {
+ Item *ord_item= *ord->item;
+ if (ord_item->real_item()->type() != Item::FIELD_ITEM) // !(7.1)
+ continue;
+
+ Field *ord_field= ((Item_field *) (ord_item->real_item()))->field;
+
+ JOIN_TAB *tab= ord_field->table->reginfo.join_tab;
+ if (tab->is_inner_table_of_outer_join())
+ continue;
+
+ List_iterator<Item> li(fields_list);
+ Item *item;
+ uint item_no= 0;
+ while ((item= li++))
+ {
+ if ((*ord->item)->eq(item, 0)) // (7.2)
+ {
+ SplM_field_ext_info new_elem;
+ new_elem.producing_item= item;
+ new_elem.item_no= item_no;
+ new_elem.mat_field= derived->table->field[item_no];
+ new_elem.underlying_field= ord_field;
+ new_elem.is_usable_for_ref_access= false;
+ candidates.push(new_elem);
+ usable_tables|= ord_field->table->map;
+ break;
+ }
+ item_no++;
+ }
+ }
+ if (candidates.elements() == 0) // no candidates satisfying (7.1) && (7.2)
+ return false;
+
+ /*
+ For each table from this join find the keys that can be used for ref access
+ of the fields mentioned in the 'array candidates'
+ */
+
+ SplM_field_ext_info *cand;
+ SplM_field_ext_info *cand_start= &candidates.at(0);
+ SplM_field_ext_info *cand_end= cand_start + candidates.elements();
+
+ for (JOIN_TAB *tab= join_tab;
+ tab < join_tab + top_join_tab_count; tab++)
+ {
+ TABLE *table= tab->table;
+ if (!(table->map & usable_tables))
+ continue;
+
+ table->keys_usable_for_splitting.clear_all();
+ uint i;
+ for (i= 0; i < table->s->keys; i++)
+ {
+ if (!table->keys_in_use_for_query.is_set(i))
+ continue;
+ KEY *key_info= table->key_info + i;
+ uint key_parts= table->actual_n_key_parts(key_info);
+ uint usable_kp_cnt= 0;
+ for ( ; usable_kp_cnt < key_parts; usable_kp_cnt++)
+ {
+ if (key_info->actual_rec_per_key(usable_kp_cnt) == 0)
+ break;
+ int fldnr= key_info->key_part[usable_kp_cnt].fieldnr;
+
+ for (cand= cand_start; cand < cand_end; cand++)
+ {
+ if (cand->underlying_field->field_index + 1 == fldnr)
+ {
+ cand->is_usable_for_ref_access= true;
+ break;
+ }
+ }
+ if (cand == cand_end)
+ break;
+ }
+ if (usable_kp_cnt)
+ table->keys_usable_for_splitting.set_bit(i);
+ }
+ }
+
+ /* Count the candidate fields that can be accessed by ref */
+ uint spl_field_cnt= candidates.elements();
+ for (cand= cand_start; cand < cand_end; cand++)
+ {
+ if (!cand->is_usable_for_ref_access)
+ spl_field_cnt--;
+ }
+
+ if (!spl_field_cnt) // No candidate field can be accessed by ref => !(8)
+ return false;
+
+ /*
+ Create a structure of the type SplM_opt_info and fill it with
+ the collected info on potential splittability of T
+ */
+ SplM_opt_info *spl_opt_info= new (thd->mem_root) SplM_opt_info();
+ SplM_field_info *spl_field=
+ (SplM_field_info *) (thd->calloc(sizeof(SplM_field_info) *
+ spl_field_cnt));
+
+ if (!(spl_opt_info && spl_field)) // consider T as not good for splitting
+ return false;
+
+ spl_opt_info->join= this;
+ spl_opt_info->tables_usable_for_splitting= 0;
+ spl_opt_info->spl_field_cnt= spl_field_cnt;
+ spl_opt_info->spl_fields= spl_field;
+ for (cand= cand_start; cand < cand_end; cand++)
+ {
+ if (!cand->is_usable_for_ref_access)
+ continue;
+ spl_field->producing_item= cand->producing_item;
+ spl_field->underlying_field= cand->underlying_field;
+ spl_field->mat_field= cand->mat_field;
+ spl_opt_info->tables_usable_for_splitting|=
+ cand->underlying_field->table->map;
+ spl_field++;
+ }
+
+ /* Attach this info to the table T */
+ derived->table->set_spl_opt_info(spl_opt_info);
+
+ return true;
+}
+
+
+/**
+ @brief
+ Collect info on KEY_FIELD usable for splitting
+
+ @param
+ key_field KEY_FIELD to collect info on
+
+ @details
+ The function assumes that this table is potentially splittable.
+ The function checks whether the KEY_FIELD structure key_field built for
+ this table was created for a splitting field f. If so, the function does
+ the following using info from key_field:
+ 1. Builds an equality of the form f = key_field->val that could be
+ pushed into this table.
+ 2. Creates a new KEY_FIELD structure for this equality and stores
+ a reference to this structure in this->spl_opt_info.
+*/
+
+void TABLE::add_splitting_info_for_key_field(KEY_FIELD *key_field)
+{
+ DBUG_ASSERT(spl_opt_info != NULL);
+ JOIN *join= spl_opt_info->join;
+ Field *field= key_field->field;
+ SplM_field_info *spl_field= spl_opt_info->spl_fields;
+ uint i= spl_opt_info->spl_field_cnt;
+ for ( ; i; i--, spl_field++)
+ {
+ if (spl_field->mat_field == field)
+ break;
+ }
+ if (!i) // field is not usable for splitting
+ return;
+
+ /*
+ Any equality condition that can be potentially pushed into the
+ materialized derived table is constructed now though later it may turn out
+ that it is not needed, because it is not used for splitting.
+ The reason for this is that the failure to construct it when it has to be
+ injected causes denial for further processing of the query.
+ Formally this equality is needed in the KEY_FIELD structure constructed
+ here that will be used to generate additional keyuses usable for splitting.
+ However key_field.cond could be used for this purpose (see implementations
+ of virtual function can_optimize_keypart_ref()).
+
+ The condition is built in such a form that it can be added to the WHERE
+ condition of the select that specifies this table.
+ */
+ THD *thd= in_use;
+ Item *left_item= spl_field->producing_item->build_clone(thd);
+ Item *right_item= key_field->val->build_clone(thd);
+ Item_func_eq *eq_item= 0;
+ if (left_item && right_item)
+ {
+ right_item->walk(&Item::set_fields_as_dependent_processor,
+ false, join->select_lex);
+ right_item->update_used_tables();
+ eq_item= new (thd->mem_root) Item_func_eq(thd, left_item, right_item);
+ }
+ if (!eq_item)
+ return;
+ KEY_FIELD *added_key_field=
+ (KEY_FIELD *) thd->alloc(sizeof(KEY_FIELD));
+ if (!added_key_field ||
+ spl_opt_info->added_key_fields.push_back(added_key_field,thd->mem_root))
+ return;
+ added_key_field->field= spl_field->underlying_field;
+ added_key_field->cond= eq_item;
+ added_key_field->val= key_field->val;
+ added_key_field->level= 0;
+ added_key_field->optimize= KEY_OPTIMIZE_EQ;
+ added_key_field->eq_func= true;
+ added_key_field->null_rejecting= true;
+ added_key_field->cond_guard= NULL;
+ added_key_field->sj_pred_no= UINT_MAX;
+ return;
+}
+
+
+static bool
+add_ext_keyuse_for_splitting(Dynamic_array<KEYUSE_EXT> *ext_keyuses,
+ KEY_FIELD *added_key_field, uint key, uint part)
+{
+ KEYUSE_EXT keyuse_ext;
+ Field *field= added_key_field->field;
+
+ JOIN_TAB *tab=field->table->reginfo.join_tab;
+ key_map possible_keys=field->get_possible_keys();
+ possible_keys.intersect(field->table->keys_usable_for_splitting);
+ tab->keys.merge(possible_keys);
+
+ Item_func_eq *eq_item= (Item_func_eq *) (added_key_field->cond);
+ keyuse_ext.table= field->table;
+ keyuse_ext.val= eq_item->arguments()[1];
+ keyuse_ext.key= key;
+ keyuse_ext.keypart=part;
+ keyuse_ext.keypart_map= (key_part_map) 1 << part;
+ keyuse_ext.used_tables= keyuse_ext.val->used_tables();
+ keyuse_ext.optimize= added_key_field->optimize & KEY_OPTIMIZE_REF_OR_NULL;
+ keyuse_ext.ref_table_rows= 0;
+ keyuse_ext.null_rejecting= added_key_field->null_rejecting;
+ keyuse_ext.cond_guard= added_key_field->cond_guard;
+ keyuse_ext.sj_pred_no= added_key_field->sj_pred_no;
+ keyuse_ext.validity_ref= 0;
+ keyuse_ext.needed_in_prefix= added_key_field->val->used_tables();
+ keyuse_ext.validity_var= false;
+ return ext_keyuses->push(keyuse_ext);
+}
+
+
+static int
+sort_ext_keyuse(KEYUSE_EXT *a, KEYUSE_EXT *b)
+{
+ if (a->table->tablenr != b->table->tablenr)
+ return (int) (a->table->tablenr - b->table->tablenr);
+ if (a->key != b->key)
+ return (int) (a->key - b->key);
+ return (int) (a->keypart - b->keypart);
+}
+
+
+static void
+sort_ext_keyuses(Dynamic_array<KEYUSE_EXT> *keyuses)
+{
+ KEYUSE_EXT *first_keyuse= &keyuses->at(0);
+ my_qsort(first_keyuse, keyuses->elements(), sizeof(KEYUSE_EXT),
+ (qsort_cmp) sort_ext_keyuse);
+}
+
+
+/**
+ @brief
+ Add info on keyuses usable for splitting into an array
+*/
+
+static bool
+add_ext_keyuses_for_splitting_field(Dynamic_array<KEYUSE_EXT> *ext_keyuses,
+ KEY_FIELD *added_key_field)
+{
+ Field *field= added_key_field->field;
+ TABLE *table= field->table;
+ for (uint key= 0; key < table->s->keys; key++)
+ {
+ if (!(table->keys_usable_for_splitting.is_set(key)))
+ continue;
+ KEY *key_info= table->key_info + key;
+ uint key_parts= table->actual_n_key_parts(key_info);
+ KEY_PART_INFO *key_part_info= key_info->key_part;
+ for (uint part=0; part < key_parts; part++, key_part_info++)
+ {
+ if (!field->eq(key_part_info->field))
+ continue;
+ if (add_ext_keyuse_for_splitting(ext_keyuses, added_key_field, key, part))
+ return true;
+ }
+ }
+ return false;
+}
+
+
+/*
+ @brief
+ Cost of the post join operation used in specification of splittable table
+*/
+
+static
+double spl_postjoin_oper_cost(THD *thd, double join_record_count, uint rec_len)
+{
+ double cost;
+ cost= get_tmp_table_write_cost(thd, join_record_count,rec_len) *
+ join_record_count; // cost to fill tmp table
+ cost+= get_tmp_table_lookup_cost(thd, join_record_count,rec_len) *
+ join_record_count; // cost to perform post join operation used here
+ cost+= get_tmp_table_lookup_cost(thd, join_record_count, rec_len) +
+ join_record_count * log2 (join_record_count) *
+ SORT_INDEX_CMP_COST; // cost to perform sorting
+ return cost;
+}
+
+/**
+ @brief
+ Add KEYUSE structures that can be usable for splitting
+
+ @details
+ This function is called only for joins created for potentially
+ splittable materialized tables. The function does the following:
+ 1. Creates the dynamic array ext_keyuses_for_splitting of KEYUSE_EXT
+ structures and fills is with info about all keyuses that
+ could be used for splitting.
+ 2. Sort the array ext_keyuses_for_splitting for fast access by key
+ on certain columns.
+ 3. Collects and stores cost and cardinality info on the best execution
+ plan that does not use splitting and save this plan together with
+ corresponding array of keyuses.
+ 4. Expand this array with KEYUSE elements built from the info stored
+ in ext_keyuses_for_splitting that could be produced by pushed
+ equalities employed for splitting.
+ 5. Prepare the extended array of keyuses to be used in the function
+ best_access_plan()
+*/
+
+void JOIN::add_keyuses_for_splitting()
+{
+ uint i;
+ uint idx;
+ KEYUSE_EXT *keyuse_ext;
+ KEYUSE_EXT keyuse_ext_end;
+ double oper_cost;
+ uint rec_len;
+ uint added_keyuse_count;
+ TABLE *table= select_lex->master_unit()->derived->table;
+ List_iterator_fast<KEY_FIELD> li(spl_opt_info->added_key_fields);
+ KEY_FIELD *added_key_field;
+ if (!spl_opt_info->added_key_fields.elements)
+ goto err;
+ if (!(ext_keyuses_for_splitting= new Dynamic_array<KEYUSE_EXT>))
+ goto err;
+ while ((added_key_field= li++))
+ {
+ (void) add_ext_keyuses_for_splitting_field(ext_keyuses_for_splitting,
+ added_key_field);
+ }
+ added_keyuse_count= ext_keyuses_for_splitting->elements();
+ if (!added_keyuse_count)
+ goto err;
+ sort_ext_keyuses(ext_keyuses_for_splitting);
+ bzero((char*) &keyuse_ext_end, sizeof(keyuse_ext_end));
+ if (ext_keyuses_for_splitting->push(keyuse_ext_end))
+ goto err;
+
+ spl_opt_info->unsplit_card= join_record_count;
+
+ rec_len= table->s->rec_buff_length;
+
+ oper_cost= spl_postjoin_oper_cost(thd, join_record_count, rec_len);
+
+ spl_opt_info->unsplit_cost= best_positions[table_count-1].read_time +
+ oper_cost;
+
+ if (!(save_qep= new Join_plan_state(table_count + 1)))
+ goto err;
+
+ save_query_plan(save_qep);
+
+ if (!keyuse.buffer &&
+ my_init_dynamic_array(&keyuse, sizeof(KEYUSE), 20, 64,
+ MYF(MY_THREAD_SPECIFIC)))
+ goto err;
+
+ if (allocate_dynamic(&keyuse,
+ save_qep->keyuse.elements +
+ added_keyuse_count))
+ goto err;
+
+ memcpy(keyuse.buffer,
+ save_qep->keyuse.buffer,
+ (size_t) save_qep->keyuse.elements * keyuse.size_of_element);
+ keyuse.elements= save_qep->keyuse.elements;
+
+ keyuse_ext= &ext_keyuses_for_splitting->at(0);
+ idx= save_qep->keyuse.elements;
+ for (i=0; i < added_keyuse_count; i++, keyuse_ext++, idx++)
+ {
+ set_dynamic(&keyuse, (KEYUSE *) keyuse_ext, idx);
+ KEYUSE *added_keyuse= ((KEYUSE *) (keyuse.buffer)) + idx;
+ added_keyuse->validity_ref= &keyuse_ext->validity_var;
+ }
+
+ if (sort_and_filter_keyuse(thd, &keyuse, true))
+ goto err;
+ optimize_keyuse(this, &keyuse);
+
+ for (uint i= 0; i < table_count; i++)
+ {
+ JOIN_TAB *tab= join_tab + i;
+ map2table[tab->table->tablenr]= tab;
+ }
+
+ return;
+
+err:
+ if (save_qep)
+ restore_query_plan(save_qep);
+ table->deny_splitting();
+ return;
+}
+
+
+/**
+ @brief
+ Add KEYUSE structures that can be usable for splitting of this joined table
+*/
+
+void JOIN_TAB::add_keyuses_for_splitting()
+{
+ DBUG_ASSERT(table->spl_opt_info != NULL);
+ SplM_opt_info *spl_opt_info= table->spl_opt_info;
+ spl_opt_info->join->add_keyuses_for_splitting();
+}
+
+
+/*
+ @brief
+ Find info on the splitting plan by the splitting key
+*/
+
+SplM_plan_info *SplM_opt_info::find_plan(TABLE *table, uint key, uint parts)
+{
+ List_iterator_fast<SplM_plan_info> li(plan_cache);
+ SplM_plan_info *spl_plan;
+ while ((spl_plan= li++))
+ {
+ if (spl_plan->table == table &&
+ spl_plan->key == key &&
+ spl_plan->parts == parts)
+ break;
+ }
+ return spl_plan;
+}
+
+
+/*
+ @breaf
+ Enable/Disable a keyuses that can be used for splitting
+ */
+
+static
+void reset_validity_vars_for_keyuses(KEYUSE_EXT *key_keyuse_ext_start,
+ TABLE *table, uint key,
+ table_map remaining_tables,
+ bool validity_val)
+{
+ KEYUSE_EXT *keyuse_ext= key_keyuse_ext_start;
+ do
+ {
+ if (!(keyuse_ext->needed_in_prefix & remaining_tables))
+ {
+ /*
+ The enabling/disabling flags are set just in KEYUSE_EXT structures.
+ Yet keyuses that are used by best_access_path() have pointers
+ to these flags.
+ */
+ keyuse_ext->validity_var= validity_val;
+ }
+ keyuse_ext++;
+ }
+ while (keyuse_ext->key == key && keyuse_ext->table == table);
+}
+
+
+/**
+ @brief
+ Choose the best splitting to extend the evaluated partial join
+
+ @param
+ record_count estimated cardinality of the extended partial join
+ remaining_tables tables not joined yet
+
+ @details
+ This function is called during the search for the best execution
+ plan of the join that contains this table T. The function is called
+ every time when the optimizer tries to extend a partial join by
+ joining it with table T. Depending on what tables are already in the
+ partial join different equalities usable for splitting can be pushed
+ into T. The function evaluates different variants and chooses the
+ best one. Then the function finds the plan for the materializing join
+ with the chosen equality conditions pushed into it. If the cost of the
+ plan turns out to be less than the cost of the best plan without
+ splitting the function set it as the true plan of materialization
+ of the table T.
+ The function caches the found plans for materialization of table T
+ together if the info what key was used for splitting. Next time when
+ the optimizer prefers to use the same key the plan is taken from
+ the cache of plans
+
+ @retval
+ Pointer to the info on the found plan that employs the pushed equalities
+ if the plan has been chosen, NULL - otherwise.
+*/
+
+SplM_plan_info * JOIN_TAB::choose_best_splitting(double record_count,
+ table_map remaining_tables)
+{
+ SplM_opt_info *spl_opt_info= table->spl_opt_info;
+ DBUG_ASSERT(spl_opt_info != NULL);
+ JOIN *join= spl_opt_info->join;
+ THD *thd= join->thd;
+ table_map tables_usable_for_splitting=
+ spl_opt_info->tables_usable_for_splitting;
+ KEYUSE_EXT *keyuse_ext= &join->ext_keyuses_for_splitting->at(0);
+ KEYUSE_EXT *best_key_keyuse_ext_start;
+ TABLE *best_table= 0;
+ double best_rec_per_key= DBL_MAX;
+ SplM_plan_info *spl_plan= 0;
+ uint best_key;
+ uint best_key_parts;
+
+ /*
+ Check whether there are keys that can be used to join T employing splitting
+ and if so, select the best out of such keys
+ */
+ for (uint tablenr= 0; tablenr < join->table_count; tablenr++)
+ {
+ if (!((1 << tablenr) & tables_usable_for_splitting))
+ continue;
+ JOIN_TAB *tab= join->map2table[tablenr];
+ TABLE *table= tab->table;
+ do
+ {
+ uint key= keyuse_ext->key;
+ KEYUSE_EXT *key_keyuse_ext_start= keyuse_ext;
+ key_part_map found_parts= 0;
+ do
+ {
+ if (keyuse_ext->needed_in_prefix & remaining_tables)
+ {
+ keyuse_ext++;
+ continue;
+ }
+ if (!(keyuse_ext->keypart_map & found_parts))
+ {
+ if ((!found_parts && !keyuse_ext->keypart) ||
+ (found_parts && ((keyuse_ext->keypart_map >> 1) & found_parts)))
+ found_parts|= keyuse_ext->keypart_map;
+ else
+ {
+ do
+ {
+ keyuse_ext++;
+ }
+ while (keyuse_ext->key == key && keyuse_ext->table == table);
+ break;
+ }
+ }
+ KEY *key_info= table->key_info + key;
+ double rec_per_key=
+ key_info->actual_rec_per_key(keyuse_ext->keypart);
+ if (rec_per_key < best_rec_per_key)
+ {
+ best_table= keyuse_ext->table;
+ best_key= keyuse_ext->key;
+ best_key_parts= keyuse_ext->keypart + 1;
+ best_rec_per_key= rec_per_key;
+ best_key_keyuse_ext_start= key_keyuse_ext_start;
+ }
+ keyuse_ext++;
+ }
+ while (keyuse_ext->key == key && keyuse_ext->table == table);
+ }
+ while (keyuse_ext->table == table);
+ }
+ if (best_table)
+ {
+ /*
+ The key for splitting was chosen, look for the plan for this key
+ in the cache
+ */
+ spl_plan= spl_opt_info->find_plan(best_table, best_key, best_key_parts);
+ if (!spl_plan &&
+ (spl_plan= (SplM_plan_info *) thd->alloc(sizeof(SplM_plan_info))) &&
+ (spl_plan->best_positions=
+ (POSITION *) thd->alloc(sizeof(POSITION) * join->table_count)) &&
+ !spl_opt_info->plan_cache.push_back(spl_plan))
+ {
+ /*
+ The plan for the chosen key has not been found in the cache.
+ Build a new plan and save info on it in the cache
+ */
+ table_map all_table_map= (1 << join->table_count) - 1;
+ reset_validity_vars_for_keyuses(best_key_keyuse_ext_start, best_table,
+ best_key, remaining_tables, true);
+ choose_plan(join, all_table_map & ~join->const_table_map);
+ spl_plan->keyuse_ext_start= best_key_keyuse_ext_start;
+ spl_plan->table= best_table;
+ spl_plan->key= best_key;
+ spl_plan->parts= best_key_parts;
+ spl_plan->split_sel= best_rec_per_key / spl_opt_info->unsplit_card;
+
+ uint rec_len= table->s->rec_buff_length;
+
+ double split_card= spl_opt_info->unsplit_card * spl_plan->split_sel;
+ double oper_cost= split_card *
+ spl_postjoin_oper_cost(thd, split_card, rec_len);
+ spl_plan->cost= join->best_positions[join->table_count-1].read_time +
+ + oper_cost;
+
+ memcpy((char *) spl_plan->best_positions,
+ (char *) join->best_positions,
+ sizeof(POSITION) * join->table_count);
+ reset_validity_vars_for_keyuses(best_key_keyuse_ext_start, best_table,
+ best_key, remaining_tables, false);
+ }
+ spl_opt_info->last_plan= 0;
+ if (spl_plan)
+ {
+ if(record_count * spl_plan->cost < spl_opt_info->unsplit_cost)
+ {
+ /*
+ The best plan that employs splitting is cheaper than
+ the plan without splitting
+ */
+ spl_opt_info->last_plan= spl_plan;
+ }
+ }
+ }
+
+ /* Set the cost of the preferred materialization for this partial join */
+ records= spl_opt_info->unsplit_card;
+ spl_plan= spl_opt_info->last_plan;
+ if (spl_plan)
+ {
+ startup_cost= record_count * spl_plan->cost;
+ records= (ha_rows) (records * spl_plan->split_sel);
+ }
+ else
+ startup_cost= spl_opt_info->unsplit_cost;
+ return spl_plan;
+}
+
+
+/**
+ @brief
+ Inject equalities for splitting used by the materialization join
+
+ @param
+ remaining_tables used to filter out the equalities that cannot
+ be pushed.
+
+ @details
+ This function is called by JOIN_TAB::fix_splitting that is used
+ to fix the chosen splitting of a splittable materialized table T
+ in the final query execution plan. In this plan the table T
+ is joined just before the 'remaining_tables'. So all equalities
+ usable for splitting whose right parts do not depend on any of
+ remaining tables can be pushed into join for T.
+ The function also marks the select that specifies T as
+ UNCACHEABLE_DEPENDENT_INJECTED.
+
+ @retval
+ false on success
+ true on failure
+*/
+
+bool JOIN::inject_best_splitting_cond(table_map remaining_tables)
+{
+ Item *inj_cond= 0;
+ List<Item> inj_cond_list;
+ List_iterator<KEY_FIELD> li(spl_opt_info->added_key_fields);
+ KEY_FIELD *added_key_field;
+ while ((added_key_field= li++))
+ {
+ if (remaining_tables & added_key_field->val->used_tables())
+ continue;
+ if (inj_cond_list.push_back(added_key_field->cond, thd->mem_root))
+ return true;
+ }
+ DBUG_ASSERT(inj_cond_list.elements);
+ switch (inj_cond_list.elements) {
+ case 1:
+ inj_cond= inj_cond_list.head(); break;
+ default:
+ inj_cond= new (thd->mem_root) Item_cond_and(thd, inj_cond_list);
+ if (!inj_cond)
+ return true;
+ }
+ if (inj_cond)
+ inj_cond->fix_fields(thd,0);
+
+ if (inject_cond_into_where(inj_cond))
+ return true;
+
+ select_lex->uncacheable|= UNCACHEABLE_DEPENDENT_INJECTED;
+ st_select_lex_unit *unit= select_lex->master_unit();
+ unit->uncacheable|= UNCACHEABLE_DEPENDENT_INJECTED;
+
+ return false;
+}
+
+
+/**
+ @brief
+ Fix the splitting chosen for a splittable table in the final query plan
+
+ @param
+ spl_plan info on the splitting plan chosen for the splittable table T
+ remaining_tables the table T is joined just before these tables
+
+ @details
+ If in the final query plan the optimizer has chosen a splitting plan
+ then the function sets this plan as the final execution plan to
+ materialized the table T. Otherwise the plan that does not use
+ splitting is set for the materialization.
+
+ @retval
+ false on success
+ true on failure
+*/
+
+bool JOIN_TAB::fix_splitting(SplM_plan_info *spl_plan,
+ table_map remaining_tables)
+{
+ SplM_opt_info *spl_opt_info= table->spl_opt_info;
+ DBUG_ASSERT(table->spl_opt_info != 0);
+ JOIN *md_join= spl_opt_info->join;
+ if (spl_plan)
+ {
+ memcpy((char *) md_join->best_positions,
+ (char *) spl_plan->best_positions,
+ sizeof(POSITION) * md_join->table_count);
+ if (md_join->inject_best_splitting_cond(remaining_tables))
+ return true;
+ /*
+ This is called for a proper work of JOIN::get_best_combination()
+ called for the join that materializes T
+ */
+ reset_validity_vars_for_keyuses(spl_plan->keyuse_ext_start,
+ spl_plan->table,
+ spl_plan->key,
+ remaining_tables,
+ true);
+ }
+ else
+ {
+ md_join->restore_query_plan(md_join->save_qep);
+ }
+ return false;
+}
+
+
+/**
+ @brief
+ Fix the splittings chosen splittable tables in the final query plan
+
+ @details
+ The function calls JOIN_TAB::fix_splittins for all potentially
+ splittable tables in this join to set all final materialization
+ plans chosen for these tables.
+
+ @retval
+ false on success
+ true on failure
+*/
+
+bool JOIN::fix_all_splittings_in_plan()
+{
+ table_map prev_tables= 0;
+ table_map all_tables= (1 << table_count) - 1;
+ for (uint tablenr=0 ; tablenr < table_count ; tablenr++)
+ {
+ POSITION *cur_pos= &best_positions[tablenr];
+ JOIN_TAB *tab= cur_pos->table;
+ if (tab->table->is_splittable())
+ {
+ SplM_plan_info *spl_plan= cur_pos->spl_plan;
+ if (tab->fix_splitting(spl_plan, all_tables & ~prev_tables))
+ return true;
+ }
+ prev_tables|= tab->table->map;
+ }
+ return false;
+}
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index 9cd2eedb55d..dada23508b5 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -446,10 +446,6 @@ static bool convert_subq_to_jtbm(JOIN *parent_join,
Item_in_subselect *subq_pred, bool *remove);
static TABLE_LIST *alloc_join_nest(THD *thd);
static uint get_tmp_table_rec_length(Ref_ptr_array p_list, uint elements);
-static double get_tmp_table_lookup_cost(THD *thd, double row_count,
- uint row_size);
-static double get_tmp_table_write_cost(THD *thd, double row_count,
- uint row_size);
bool find_eq_ref_candidate(TABLE *table, table_map sj_inner_tables);
static SJ_MATERIALIZATION_INFO *
at_sjmat_pos(const JOIN *join, table_map remaining_tables, const JOIN_TAB *tab,
@@ -2468,7 +2464,7 @@ static uint get_tmp_table_rec_length(Ref_ptr_array p_items, uint elements)
@return the cost of one lookup
*/
-static double
+double
get_tmp_table_lookup_cost(THD *thd, double row_count, uint row_size)
{
if (row_count * row_size > thd->variables.max_heap_table_size)
@@ -2488,7 +2484,7 @@ get_tmp_table_lookup_cost(THD *thd, double row_count, uint row_size)
@return the cost of writing one row
*/
-static double
+double
get_tmp_table_write_cost(THD *thd, double row_count, uint row_size)
{
double lookup_cost= get_tmp_table_lookup_cost(thd, row_count, row_size);
diff --git a/sql/sql_class.h b/sql/sql_class.h
index de56206df4b..8747d658aea 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -5507,8 +5507,6 @@ public:
};
-
-
/*
Optimizer and executor structure for the materialized semi-join info. This
structure contains
diff --git a/sql/sql_const.h b/sql/sql_const.h
index 007b7faeebb..65742235bee 100644
--- a/sql/sql_const.h
+++ b/sql/sql_const.h
@@ -231,6 +231,7 @@
*/
#define HEAP_TEMPTABLE_LOOKUP_COST 0.05
#define DISK_TEMPTABLE_LOOKUP_COST 1.0
+#define SORT_INDEX_CMP_COST 0.02
#define MY_CHARSET_BIN_MB_MAXLEN 1
diff --git a/sql/sql_priv.h b/sql/sql_priv.h
index f40ac6f2663..ba37d933f12 100644
--- a/sql/sql_priv.h
+++ b/sql/sql_priv.h
@@ -227,7 +227,7 @@
#define OPTIMIZER_SWITCH_EXISTS_TO_IN (1ULL << 28)
#define OPTIMIZER_SWITCH_ORDERBY_EQ_PROP (1ULL << 29)
#define OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED (1ULL << 30)
-#define OPTIMIZER_SWITCH_SPLIT_GROUPING_DERIVED (1ULL << 31)
+#define OPTIMIZER_SWITCH_SPLIT_MATERIALIZED (1ULL << 31)
#define OPTIMIZER_SWITCH_DEFAULT (OPTIMIZER_SWITCH_INDEX_MERGE | \
OPTIMIZER_SWITCH_INDEX_MERGE_UNION | \
@@ -254,7 +254,7 @@
OPTIMIZER_SWITCH_EXISTS_TO_IN | \
OPTIMIZER_SWITCH_ORDERBY_EQ_PROP | \
OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED | \
- OPTIMIZER_SWITCH_SPLIT_GROUPING_DERIVED)
+ OPTIMIZER_SWITCH_SPLIT_MATERIALIZED)
/*
Replication uses 8 bytes to store SQL_MODE in the binary log. The day you
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 96aa227b439..82539865d41 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -85,7 +85,6 @@ LEX_CSTRING distinct_key= {STRING_WITH_LEN("distinct_key")};
struct st_sargable_param;
-static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array);
static bool make_join_statistics(JOIN *join, List<TABLE_LIST> &leaves,
DYNAMIC_ARRAY *keyuse);
static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,
@@ -93,8 +92,6 @@ static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,
uint tables, COND *conds,
table_map table_map, SELECT_LEX *select_lex,
SARGABLE_PARAM **sargables);
-static bool sort_and_filter_keyuse(THD *thd, DYNAMIC_ARRAY *keyuse,
- bool skip_unprefixed_keyparts);
static int sort_keyuse(KEYUSE *a,KEYUSE *b);
static bool are_tables_local(JOIN_TAB *jtab, table_map used_tables);
static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
@@ -1125,7 +1122,6 @@ int JOIN::optimize()
if (optimization_state != JOIN::NOT_OPTIMIZED)
return FALSE;
optimization_state= JOIN::OPTIMIZATION_IN_PROGRESS;
- is_for_splittable_grouping_derived= false;
res= optimize_inner();
}
if (!with_two_phase_optimization ||
@@ -1571,9 +1567,6 @@ int JOIN::optimize_stage2()
if (subq_exit_fl)
goto setup_subq_exit;
- if (select_lex->handle_derived(thd->lex, DT_OPTIMIZE))
- DBUG_RETURN(1);
-
if (thd->check_killed())
DBUG_RETURN(1);
@@ -1581,6 +1574,9 @@ int JOIN::optimize_stage2()
if (get_best_combination())
DBUG_RETURN(1);
+ if (select_lex->handle_derived(thd->lex, DT_OPTIMIZE))
+ DBUG_RETURN(1);
+
if (optimizer_flag(thd, OPTIMIZER_SWITCH_DERIVED_WITH_KEYS))
drop_unused_derived_keys();
@@ -3670,7 +3666,11 @@ JOIN::destroy()
cleanup_item_list(tmp_all_fields1);
cleanup_item_list(tmp_all_fields3);
destroy_sj_tmp_tables(this);
- delete_dynamic(&keyuse);
+ delete_dynamic(&keyuse);
+ if (save_qep)
+ delete(save_qep);
+ if (ext_keyuses_for_splitting)
+ delete(ext_keyuses_for_splitting);
delete procedure;
DBUG_RETURN(error);
}
@@ -4124,6 +4124,12 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
DBUG_EXECUTE("opt", print_keyuse_array(keyuse_array););
}
+ for (s= stat; s < stat_end; s++)
+ {
+ if (s->table->is_splittable())
+ s->add_keyuses_for_splitting();
+ }
+
join->const_table_map= no_rows_const_tables;
join->const_tables= const_count;
eliminate_tables(join);
@@ -4597,9 +4603,6 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
if (join->choose_subquery_plan(all_table_map & ~join->const_table_map))
goto error;
- if (join->improve_chosen_plan(join->thd))
- goto error;
-
DEBUG_SYNC(join->thd, "inside_make_join_statistics");
DBUG_RETURN(0);
@@ -4629,23 +4632,6 @@ error:
keyuse Pointer to possible keys
*****************************************************************************/
-/// Used when finding key fields
-struct KEY_FIELD {
- Field *field;
- Item_bool_func *cond;
- Item *val; ///< May be empty if diff constant
- uint level;
- uint optimize;
- bool eq_func;
- /**
- If true, the condition this struct represents will not be satisfied
- when val IS NULL.
- */
- bool null_rejecting;
- bool *cond_guard; /* See KEYUSE::cond_guard */
- uint sj_pred_no; /* See KEYUSE::sj_pred_no */
-};
-
/**
Merge new key definitions to old ones, remove those not used in both.
@@ -5296,7 +5282,7 @@ Item_func_ne::add_key_fields(JOIN *join, KEY_FIELD **key_fields,
/*
QQ: perhaps test for !is_local_field(args[1]) is not really needed here.
Other comparison functions, e.g. Item_func_le, Item_func_gt, etc,
- do not have this test. See Item_bool_func2::add_key_field_optimize_op().
+ do not have this test. See Item_bool_func2::add_key_fieldoptimize_op().
Check with the optimizer team.
*/
if (is_local_field(args[0]) && !is_local_field(args[1]))
@@ -5479,6 +5465,7 @@ add_keyuse(DYNAMIC_ARRAY *keyuse_array, KEY_FIELD *key_field,
keyuse.null_rejecting= key_field->null_rejecting;
keyuse.cond_guard= key_field->cond_guard;
keyuse.sj_pred_no= key_field->sj_pred_no;
+ keyuse.validity_ref= 0;
return (insert_dynamic(keyuse_array,(uchar*) &keyuse));
}
@@ -5524,7 +5511,9 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array, KEY_FIELD *key_field)
key_field->val->used_tables())
{
if (!field->can_optimize_hash_join(key_field->cond, key_field->val))
- return false;
+ return false;
+ if (form->is_splittable())
+ form->add_splitting_info_for_key_field(key_field);
/*
If a key use is extracted from an equi-join predicate then it is
added not only as a key use for every index whose component can
@@ -5538,7 +5527,6 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array, KEY_FIELD *key_field)
return FALSE;
}
-
static bool
add_ft_keys(DYNAMIC_ARRAY *keyuse_array,
JOIN_TAB *stat,COND *cond,table_map usable_tables)
@@ -5600,6 +5588,7 @@ add_ft_keys(DYNAMIC_ARRAY *keyuse_array,
keyuse.optimize= 0;
keyuse.keypart_map= 0;
keyuse.sj_pred_no= UINT_MAX;
+ keyuse.validity_ref= 0;
return insert_dynamic(keyuse_array,(uchar*) &keyuse);
}
@@ -5887,8 +5876,8 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
Special treatment for ft-keys.
*/
-static bool sort_and_filter_keyuse(THD *thd, DYNAMIC_ARRAY *keyuse,
- bool skip_unprefixed_keyparts)
+bool sort_and_filter_keyuse(THD *thd, DYNAMIC_ARRAY *keyuse,
+ bool skip_unprefixed_keyparts)
{
KEYUSE key_end, *prev, *save_pos, *use;
uint found_eq_constant, i;
@@ -5956,7 +5945,7 @@ static bool sort_and_filter_keyuse(THD *thd, DYNAMIC_ARRAY *keyuse,
Update some values in keyuse for faster choose_plan() loop.
*/
-static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array)
+void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array)
{
KEYUSE *end,*keyuse= dynamic_element(keyuse_array, 0, KEYUSE*);
@@ -5997,7 +5986,6 @@ static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array)
}
-
/**
Check for the presence of AGGFN(DISTINCT a) queries that may be subject
to loose index scan.
@@ -6305,6 +6293,7 @@ best_access_path(JOIN *join,
bool best_uses_jbuf= FALSE;
MY_BITMAP *eq_join_set= &s->table->eq_join_set;
KEYUSE *hj_start_key= 0;
+ SplM_plan_info *spl_plan= 0;
disable_jbuf= disable_jbuf || idx == join->const_tables;
@@ -6314,7 +6303,10 @@ best_access_path(JOIN *join,
bitmap_clear_all(eq_join_set);
loose_scan_opt.init(join, s, remaining_tables);
-
+
+ if (s->table->is_splittable())
+ spl_plan= s->choose_best_splitting(record_count, remaining_tables);
+
if (s->keyuse)
{ /* Use key if possible */
KEYUSE *keyuse;
@@ -6379,6 +6371,7 @@ best_access_path(JOIN *join,
2. we won't get two ref-or-null's
*/
if (!(remaining_tables & keyuse->used_tables) &&
+ (!keyuse->validity_ref || *keyuse->validity_ref) &&
s->access_from_tables_is_allowed(keyuse->used_tables,
join->sjm_lookup_tables) &&
!(ref_or_null_part && (keyuse->optimize &
@@ -6691,6 +6684,7 @@ best_access_path(JOIN *join,
tmp += s->startup_cost;
loose_scan_opt.check_ref_access_part2(key, start_key, records, tmp);
} /* not ft_key */
+
if (tmp + 0.0001 < best_time - records/(double) TIME_FOR_COMPARE)
{
best_time= tmp + records/(double) TIME_FOR_COMPARE;
@@ -6878,6 +6872,7 @@ best_access_path(JOIN *join,
pos->ref_depend_map= best_ref_depends_map;
pos->loosescan_picker.loosescan_key= MAX_KEY;
pos->use_join_buffer= best_uses_jbuf;
+ pos->spl_plan= spl_plan;
loose_scan_opt.save_to_position(s, loose_scan_pos);
@@ -8932,192 +8927,15 @@ JOIN_TAB *next_depth_first_tab(JOIN* join, JOIN_TAB* tab)
return tab;
}
-static
-bool key_can_be_used_to_split_by_fields(KEY *key_info, uint used_key_parts,
- List<Field> &fields)
-{
- if (used_key_parts < fields.elements)
- return false;
- List_iterator_fast<Field> li(fields);
- Field *fld;
- KEY_PART_INFO *start= key_info->key_part;
- KEY_PART_INFO *end= start + fields.elements;
- while ((fld= li++))
- {
- KEY_PART_INFO *key_part;
- for (key_part= start; key_part < end; key_part++)
- {
- if (key_part->fieldnr == fld->field_index + 1)
- break;
- }
- if (key_part == end)
- return false;
- }
- return true;
-}
-
-bool JOIN::check_for_splittable_grouping_derived(THD *thd)
-{
- partition_list= 0;
- st_select_lex_unit *unit= select_lex->master_unit();
- TABLE_LIST *derived= unit->derived;
- if (!optimizer_flag(thd, OPTIMIZER_SWITCH_SPLIT_GROUPING_DERIVED))
- return false;
- if (!(derived && derived->is_materialized_derived()))
- return false;
- if (unit->first_select()->next_select())
- return false;
- if (derived->prohibit_cond_pushdown)
- return false;
- if (derived->is_recursive_with_table())
- return false;
- if (group_list)
- {
- if (!select_lex->have_window_funcs())
- partition_list= group_list;
- }
- else if (select_lex->have_window_funcs() &&
- select_lex->window_specs.elements == 1)
- {
- partition_list=
- select_lex->window_specs.head()->partition_list->first;
- }
- if (!partition_list)
- return false;
-
- ORDER *ord;
- TABLE *table= 0;
- key_map ref_keys;
- uint group_fields= 0;
- ref_keys.set_all();
- for (ord= partition_list; ord; ord= ord->next, group_fields++)
- {
- Item *ord_item= *ord->item;
- if (ord_item->real_item()->type() != Item::FIELD_ITEM)
- return false;
- Field *ord_field= ((Item_field *) (ord_item->real_item()))->field;
- if (!table)
- table= ord_field->table;
- else if (table != ord_field->table)
- return false;
- ref_keys.intersect(ord_field->part_of_key);
- }
- if (ref_keys.is_clear_all())
- return false;
-
- uint i;
- List<Field> grouping_fields;
- List<Field> splitting_fields;
- List_iterator<Item> li(fields_list);
- for (ord= partition_list; ord; ord= ord->next)
- {
- Item *item;
- i= 0;
- while ((item= li++))
- {
- if ((*ord->item)->eq(item, 0))
- break;
- i++;
- }
- if (!item)
- return false;
- if (splitting_fields.push_back(derived->table->field[i], thd->mem_root))
- return false;
- Item_field *ord_field= (Item_field *)(item->real_item());
- if (grouping_fields.push_back(ord_field->field, thd->mem_root))
- return false;
- li.rewind();
- }
-
- for (i= 0; i < table->s->keys; i++)
- {
- if (!(ref_keys.is_set(i)))
- continue;
- KEY *key_info= table->key_info + i;
- if (key_can_be_used_to_split_by_fields(key_info,
- table->actual_n_key_parts(key_info),
- grouping_fields))
- break;
- }
- if (i == table->s->keys)
- return false;
-
- derived->table->splitting_fields= splitting_fields;
- is_for_splittable_grouping_derived= true;
- return true;
-}
-
bool JOIN::check_two_phase_optimization(THD *thd)
{
- if (!check_for_splittable_grouping_derived(thd))
- return false;
- return true;
+ if (check_for_splittable_materialized())
+ return true;
+ return false;
}
-Item *JOIN_TAB::get_splitting_cond_for_grouping_derived(THD *thd)
-{
- /* this is a stub */
- TABLE_LIST *derived= table->pos_in_table_list;
- st_select_lex *sel= derived->get_unit()->first_select();
- Item *cond= 0;
- table_map used_tables= OUTER_REF_TABLE_BIT;
- POSITION *pos= join->best_positions;
- for (; pos->table != this; pos++)
- {
- used_tables|= pos->table->table->map;
- }
-
- if (!pos->key)
- return 0;
-
- KEY *key_info= table->key_info + pos->key->key;
- if (!key_can_be_used_to_split_by_fields(key_info,
- key_info->user_defined_key_parts,
- table->splitting_fields))
- return 0;
-
- create_ref_for_key(join, this, pos->key,
- false, used_tables);
- List<Item> cond_list;
- KEY_PART_INFO *start= key_info->key_part;
- KEY_PART_INFO *end= start + table->splitting_fields.elements;
- List_iterator_fast<Field> li(table->splitting_fields);
- Field *fld= li++;
- for (ORDER *ord= sel->join->partition_list; ord;
- ord= ord->next, fld= li++)
- {
- Item *left_item= (*ord->item)->build_clone(thd);
- uint i= 0;
- for (KEY_PART_INFO *key_part= start; key_part < end; key_part++, i++)
- {
- if (key_part->fieldnr == fld->field_index + 1)
- break;
- }
- Item *right_item= ref.items[i]->build_clone(thd);
- Item_func_eq *eq_item= 0;
- right_item= right_item->build_clone(thd);
- if (left_item && right_item)
- {
- right_item->walk(&Item::set_fields_as_dependent_processor,
- false, join->select_lex);
- right_item->update_used_tables();
- eq_item= new (thd->mem_root) Item_func_eq(thd, left_item, right_item);
- }
- if (!eq_item || cond_list.push_back(eq_item, thd->mem_root))
- return 0;
- }
- switch (cond_list.elements) {
- case 0: break;
- case 1: cond= cond_list.head(); break;
- default: cond= new (thd->mem_root) Item_cond_and(thd, cond_list);
- }
- if (cond)
- cond->fix_fields(thd,0);
- return cond;
-}
-
bool JOIN::inject_cond_into_where(Item *injected_cond)
{
Item *where_item= injected_cond;
@@ -9152,48 +8970,6 @@ bool JOIN::inject_cond_into_where(Item *injected_cond)
}
-bool JOIN::push_splitting_cond_into_derived(THD *thd, Item *cond)
-{
- enum_reopt_result reopt_result= REOPT_NONE;
- table_map all_table_map= 0;
- for (JOIN_TAB *tab= join_tab;
- tab < join_tab + top_join_tab_count; tab++)
- all_table_map|= tab->table->map;
- reopt_result= reoptimize(cond, all_table_map & ~const_table_map, NULL);
- if (reopt_result == REOPT_ERROR)
- return true;
- if (inject_cond_into_where(cond))
- return true;
- if (cond->used_tables() & OUTER_REF_TABLE_BIT)
- {
- select_lex->uncacheable|= UNCACHEABLE_DEPENDENT_INJECTED;
- st_select_lex_unit *unit= select_lex->master_unit();
- unit->uncacheable|= UNCACHEABLE_DEPENDENT_INJECTED;
- }
- return false;
-}
-
-bool JOIN::improve_chosen_plan(THD *thd)
-{
- for (JOIN_TAB *tab= join_tab + const_tables;
- tab < join_tab + table_count; tab++)
- {
- TABLE_LIST *tbl= tab->table->pos_in_table_list;
- if (tbl->is_materialized_derived())
- {
- st_select_lex *sel= tbl->get_unit()->first_select();
- JOIN *derived_join= sel->join;
- if (derived_join && derived_join->is_for_splittable_grouping_derived)
- {
- Item *cond= tab->get_splitting_cond_for_grouping_derived(thd);
- if (cond && derived_join->push_splitting_cond_into_derived(thd, cond))
- return true;
- }
- }
- }
- return false;
-}
-
static Item * const null_ptr= NULL;
@@ -9262,6 +9038,9 @@ bool JOIN::get_best_combination()
full_join=0;
hash_join= FALSE;
+ if (fix_all_splittings_in_plan())
+ DBUG_RETURN(TRUE);
+
fix_semijoin_strategies_for_picked_join_order(this);
JOIN_TAB_RANGE *root_range;
@@ -9602,6 +9381,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j,
do
{
if (!(~used_tables & keyuse->used_tables) &&
+ (!keyuse->validity_ref || *keyuse->validity_ref) &&
j->keyuse_is_valid_for_access_in_chosen_plan(join, keyuse))
{
if (are_tables_local(j, keyuse->val->used_tables()))
@@ -9672,6 +9452,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j,
for (i=0 ; i < keyparts ; keyuse++,i++)
{
while (((~used_tables) & keyuse->used_tables) ||
+ (keyuse->validity_ref && !(*keyuse->validity_ref)) ||
!j->keyuse_is_valid_for_access_in_chosen_plan(join, keyuse) ||
keyuse->keypart == NO_KEYPART ||
(keyuse->keypart !=
@@ -17660,7 +17441,6 @@ err:
}
-
/****************************************************************************/
void *Virtual_tmp_table::operator new(size_t size, THD *thd) throw()
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 95e9e943c26..e1958e8ce5c 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -73,9 +73,45 @@ typedef struct keyuse_t {
*/
uint sj_pred_no;
+ /*
+ If this is NULL than KEYUSE is always enabled.
+ Otherwise it points to the enabling flag for this keyuse (true <=> enabled)
+ */
+ bool *validity_ref;
+
bool is_for_hash_join() { return is_hash_join_key_no(key); }
} KEYUSE;
+
+struct KEYUSE_EXT: public KEYUSE
+{
+ /*
+ This keyuse can be used only when the partial join being extended
+ contains the tables from this table map
+ */
+ table_map needed_in_prefix;
+ /* The enabling flag for keyuses usable for splitting */
+ bool validity_var;
+};
+
+/// Used when finding key fields
+struct KEY_FIELD {
+ Field *field;
+ Item_bool_func *cond;
+ Item *val; ///< May be empty if diff constant
+ uint level;
+ uint optimize;
+ bool eq_func;
+ /**
+ If true, the condition this struct represents will not be satisfied
+ when val IS NULL.
+ */
+ bool null_rejecting;
+ bool *cond_guard; /* See KEYUSE::cond_guard */
+ uint sj_pred_no; /* See KEYUSE::sj_pred_no */
+};
+
+
#define NO_KEYPART ((uint)(-1))
class store_key;
@@ -201,6 +237,8 @@ class SJ_TMP_TABLE;
class JOIN_TAB_RANGE;
class AGGR_OP;
class Filesort;
+struct SplM_plan_info;
+class SplM_opt_info;
typedef struct st_join_table {
st_join_table() {}
@@ -614,8 +652,10 @@ typedef struct st_join_table {
bool use_order() const; ///< Use ordering provided by chosen index?
bool sort_table();
bool remove_duplicates();
- Item *get_splitting_cond_for_grouping_derived(THD *thd);
-
+ void add_keyuses_for_splitting();
+ SplM_plan_info *choose_best_splitting(double record_count,
+ table_map remaining_tables);
+ bool fix_splitting(SplM_plan_info *spl_plan, table_map remaining_tables);
} JOIN_TAB;
@@ -920,6 +960,9 @@ typedef struct st_position
Firstmatch_picker firstmatch_picker;
LooseScan_picker loosescan_picker;
Sj_materialization_picker sjmat_picker;
+
+ /* Info on splitting plan used at this position */
+ SplM_plan_info *spl_plan;
} POSITION;
typedef Bounds_checked_array<Item_null_result*> Item_null_array;
@@ -1053,11 +1096,13 @@ protected:
/* Support for plan reoptimization with rewritten conditions. */
enum_reopt_result reoptimize(Item *added_where, table_map join_tables,
Join_plan_state *save_to);
+ /* Choose a subquery plan for a table-less subquery. */
+ bool choose_tableless_subquery_plan();
+
+public:
void save_query_plan(Join_plan_state *save_to);
void reset_query_plan();
void restore_query_plan(Join_plan_state *restore_from);
- /* Choose a subquery plan for a table-less subquery. */
- bool choose_tableless_subquery_plan();
public:
JOIN_TAB *join_tab, **best_ref;
@@ -1415,9 +1460,14 @@ public:
*/
bool implicit_grouping;
- bool is_for_splittable_grouping_derived;
bool with_two_phase_optimization;
- ORDER *partition_list;
+
+ /* Saved execution plan for this join */
+ Join_plan_state *save_qep;
+ /* Info on splittability of the table materialized by this plan*/
+ SplM_opt_info *spl_opt_info;
+ /* Contains info on keyuses usable for splitting */
+ Dynamic_array<KEYUSE_EXT> *ext_keyuses_for_splitting;
JOIN_TAB *sort_and_group_aggr_tab;
@@ -1465,7 +1515,10 @@ public:
need_distinct= 0;
skip_sort_order= 0;
with_two_phase_optimization= 0;
- is_for_splittable_grouping_derived= 0;
+ save_qep= 0;
+ spl_opt_info= 0;
+ ext_keyuses_for_splitting= 0;
+ spl_opt_info= 0;
need_tmp= 0;
hidden_group_fields= 0; /*safety*/
error= 0;
@@ -1674,10 +1727,12 @@ public:
const char *message);
JOIN_TAB *first_breadth_first_tab() { return join_tab; }
bool check_two_phase_optimization(THD *thd);
- bool check_for_splittable_grouping_derived(THD *thd);
bool inject_cond_into_where(Item *injected_cond);
- bool push_splitting_cond_into_derived(THD *thd, Item *cond);
- bool improve_chosen_plan(THD *thd);
+ bool check_for_splittable_materialized();
+ void add_keyuses_for_splitting();
+ bool inject_best_splitting_cond(table_map remaining_tables);
+ bool fix_all_splittings_in_plan();
+
bool transform_in_predicates_into_in_subq(THD *thd);
private:
/**
@@ -2295,6 +2350,11 @@ bool open_tmp_table(TABLE *table);
void setup_tmp_table_column_bitmaps(TABLE *table, uchar *bitmaps);
double prev_record_reads(POSITION *positions, uint idx, table_map found_ref);
void fix_list_after_tbl_changes(SELECT_LEX *new_parent, List<TABLE_LIST> *tlist);
+double get_tmp_table_lookup_cost(THD *thd, double row_count, uint row_size);
+double get_tmp_table_write_cost(THD *thd, double row_count, uint row_size);
+void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array);
+bool sort_and_filter_keyuse(THD *thd, DYNAMIC_ARRAY *keyuse,
+ bool skip_unprefixed_keyparts);
struct st_cond_statistic
{
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 45e93116c03..0e5192d72ad 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -2457,7 +2457,7 @@ export const char *optimizer_switch_names[]=
"exists_to_in",
"orderby_uses_equalities",
"condition_pushdown_for_derived",
- "split_grouping_derived",
+ "split_materialized",
"default",
NullS
};
diff --git a/sql/table.h b/sql/table.h
index 8d66521b9ef..017db4883f3 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -1033,6 +1033,8 @@ struct st_cond_statistic;
/* Bitmap of table's fields */
typedef Bitmap<MAX_FIELDS> Field_map;
+class SplM_opt_info;
+
struct TABLE
{
TABLE() {} /* Remove gcc warning */
@@ -1312,7 +1314,13 @@ public:
bool stats_is_read; /* Persistent statistics is read for the table */
bool histograms_are_read;
MDL_ticket *mdl_ticket;
- List<Field> splitting_fields;
+
+ /*
+ This is used only for potentially splittable materialized tables and it
+ points to the info used by the optimizer to apply splitting optimization
+ */
+ SplM_opt_info *spl_opt_info;
+ key_map keys_usable_for_splitting;
void init(THD *thd, TABLE_LIST *tl);
bool fill_item_list(List<Item> *item_list) const;
@@ -1457,6 +1465,10 @@ public:
bool with_cleanup);
Field *find_field_by_name(LEX_CSTRING *str) const;
bool export_structure(THD *thd, class Row_definition_list *defs);
+ bool is_splittable() { return spl_opt_info != NULL; }
+ void set_spl_opt_info(SplM_opt_info *spl_info);
+ void deny_splitting();
+ void add_splitting_info_for_key_field(struct KEY_FIELD *key_field);
};
diff --git a/storage/tokudb/mysql-test/tokudb/r/ext_key_1_innodb.result b/storage/tokudb/mysql-test/tokudb/r/ext_key_1_innodb.result
index 16b3571db9f..a80e1664663 100644
--- a/storage/tokudb/mysql-test/tokudb/r/ext_key_1_innodb.result
+++ b/storage/tokudb/mysql-test/tokudb/r/ext_key_1_innodb.result
@@ -1,7 +1,7 @@
drop table if exists t;
select @@optimizer_switch;
@@optimizer_switch
-index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_grouping_derived=on
+index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
create table t (id int not null, x int not null, y int not null, primary key(id), key(x)) engine=innodb;
insert into t values (0,0,0),(1,1,1),(2,2,2),(3,2,3),(4,2,4);
explain select x,id from t force index (x) where x=0 and id=0;
diff --git a/storage/tokudb/mysql-test/tokudb/r/ext_key_1_tokudb.result b/storage/tokudb/mysql-test/tokudb/r/ext_key_1_tokudb.result
index 961504412a9..96d681407fe 100644
--- a/storage/tokudb/mysql-test/tokudb/r/ext_key_1_tokudb.result
+++ b/storage/tokudb/mysql-test/tokudb/r/ext_key_1_tokudb.result
@@ -1,7 +1,7 @@
drop table if exists t;
select @@optimizer_switch;
@@optimizer_switch
-index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_grouping_derived=on
+index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
create table t (id int not null, x int not null, y int not null, primary key(id), key(x)) engine=tokudb;
insert into t values (0,0,0),(1,1,1),(2,2,2),(3,2,3),(4,2,4);
explain select x,id from t force index (x) where x=0 and id=0;
diff --git a/storage/tokudb/mysql-test/tokudb/r/ext_key_2_innodb.result b/storage/tokudb/mysql-test/tokudb/r/ext_key_2_innodb.result
index e5796f7a9b1..43737c7753e 100644
--- a/storage/tokudb/mysql-test/tokudb/r/ext_key_2_innodb.result
+++ b/storage/tokudb/mysql-test/tokudb/r/ext_key_2_innodb.result
@@ -1,7 +1,7 @@
drop table if exists t;
select @@optimizer_switch;
@@optimizer_switch
-index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_grouping_derived=on
+index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
create table t (a int not null, b int not null, c int not null, d int not null, primary key(a,b), key(c,a)) engine=innodb;
insert into t values (0,0,0,0),(0,1,0,1);
explain select c,a,b from t where c=0 and a=0 and b=1;
diff --git a/storage/tokudb/mysql-test/tokudb/r/ext_key_2_tokudb.result b/storage/tokudb/mysql-test/tokudb/r/ext_key_2_tokudb.result
index 3f1ed9971c3..1dcb1ee1b8b 100644
--- a/storage/tokudb/mysql-test/tokudb/r/ext_key_2_tokudb.result
+++ b/storage/tokudb/mysql-test/tokudb/r/ext_key_2_tokudb.result
@@ -1,7 +1,7 @@
drop table if exists t;
select @@optimizer_switch;
@@optimizer_switch
-index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_grouping_derived=on
+index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
create table t (a int not null, b int not null, c int not null, d int not null, primary key(a,b), key(c,a)) engine=tokudb;
insert into t values (0,0,0,0),(0,1,0,1);
explain select c,a,b from t where c=0 and a=0 and b=1;