Commit b729896d authored by Monty's avatar Monty

MDEV-28073 Query performance degradation in newer MariaDB versions when using many tables

The issue was that best_extension_by_limited_search() had to go through
too many plans with the same cost as there where many EQ_REF tables.

Fixed by shortcutting EQ_REF (AND REF) when the result only contains one
row. This got the optimization time down from hours to sub seconds.

The only known downside with this patch is that in some cases a table
with ref and 1 record may be used before on EQ_REF table. The faster
optimzation phase should compensate for this.
parent f7dd8799
...@@ -145,8 +145,7 @@ select * from v1 { ...@@ -145,8 +145,7 @@ select * from v1 {
} }
}, },
"rows_for_plan": 1, "rows_for_plan": 1,
"cost_for_plan": 2.404394531, "cost_for_plan": 2.404394531
"estimated_join_cardinality": 1
} }
] ]
}, },
...@@ -296,8 +295,7 @@ select * from (select * from t1 where t1.a=1)q { ...@@ -296,8 +295,7 @@ select * from (select * from t1 where t1.a=1)q {
} }
}, },
"rows_for_plan": 1, "rows_for_plan": 1,
"cost_for_plan": 2.404394531, "cost_for_plan": 2.404394531
"estimated_join_cardinality": 1
} }
] ]
}, },
...@@ -454,8 +452,7 @@ select * from v2 { ...@@ -454,8 +452,7 @@ select * from v2 {
}, },
"rows_for_plan": 1, "rows_for_plan": 1,
"cost_for_plan": 2.404394531, "cost_for_plan": 2.404394531,
"cost_for_sorting": 1, "cost_for_sorting": 1
"estimated_join_cardinality": 1
} }
] ]
}, },
...@@ -525,8 +522,7 @@ select * from v2 { ...@@ -525,8 +522,7 @@ select * from v2 {
} }
}, },
"rows_for_plan": 2, "rows_for_plan": 2,
"cost_for_plan": 2.4, "cost_for_plan": 2.4
"estimated_join_cardinality": 2
} }
] ]
}, },
...@@ -662,8 +658,7 @@ explain select * from v2 { ...@@ -662,8 +658,7 @@ explain select * from v2 {
} }
}, },
"rows_for_plan": 10, "rows_for_plan": 10,
"cost_for_plan": 4.021972656, "cost_for_plan": 4.021972656
"estimated_join_cardinality": 10
} }
] ]
}, },
...@@ -780,8 +775,7 @@ explain select * from v1 { ...@@ -780,8 +775,7 @@ explain select * from v1 {
}, },
"rows_for_plan": 10, "rows_for_plan": 10,
"cost_for_plan": 4.021972656, "cost_for_plan": 4.021972656,
"cost_for_sorting": 10, "cost_for_sorting": 10
"estimated_join_cardinality": 10
} }
] ]
}, },
...@@ -845,8 +839,7 @@ explain select * from v1 { ...@@ -845,8 +839,7 @@ explain select * from v1 {
} }
}, },
"rows_for_plan": 10, "rows_for_plan": 10,
"cost_for_plan": 12, "cost_for_plan": 12
"estimated_join_cardinality": 10
} }
] ]
}, },
...@@ -1047,7 +1040,7 @@ explain select * from t1,t2 where t1.a=t2.b+2 and t2.a= t1.b { ...@@ -1047,7 +1040,7 @@ explain select * from t1,t2 where t1.a=t2.b+2 and t2.a= t1.b {
}, },
"rows_for_plan": 100, "rows_for_plan": 100,
"cost_for_plan": 242.3759623, "cost_for_plan": 242.3759623,
"estimated_join_cardinality": 100 "pruned_by_hanging_leaf": true
} }
] ]
}, },
...@@ -1278,8 +1271,7 @@ EXPLAIN SELECT DISTINCT a FROM t1 { ...@@ -1278,8 +1271,7 @@ EXPLAIN SELECT DISTINCT a FROM t1 {
} }
}, },
"rows_for_plan": 5, "rows_for_plan": 5,
"cost_for_plan": 7.25, "cost_for_plan": 7.25
"estimated_join_cardinality": 5
} }
] ]
}, },
...@@ -1470,8 +1462,7 @@ EXPLAIN SELECT MIN(d) FROM t1 where b=2 and c=3 group by a { ...@@ -1470,8 +1462,7 @@ EXPLAIN SELECT MIN(d) FROM t1 where b=2 and c=3 group by a {
}, },
"rows_for_plan": 8, "rows_for_plan": 8,
"cost_for_plan": 3.8, "cost_for_plan": 3.8,
"cost_for_sorting": 8, "cost_for_sorting": 8
"estimated_join_cardinality": 8
} }
] ]
}, },
...@@ -1669,8 +1660,7 @@ EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104e0 GROUP BY id { ...@@ -1669,8 +1660,7 @@ EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104e0 GROUP BY id {
}, },
"rows_for_plan": 9, "rows_for_plan": 9,
"cost_for_plan": 4.15, "cost_for_plan": 4.15,
"cost_for_sorting": 9, "cost_for_sorting": 9
"estimated_join_cardinality": 9
} }
] ]
}, },
...@@ -1857,8 +1847,7 @@ EXPLAIN SELECT * FROM t1 WHERE a = 20010104e0 GROUP BY id { ...@@ -1857,8 +1847,7 @@ EXPLAIN SELECT * FROM t1 WHERE a = 20010104e0 GROUP BY id {
}, },
"rows_for_plan": 9, "rows_for_plan": 9,
"cost_for_plan": 4.15, "cost_for_plan": 4.15,
"cost_for_sorting": 9, "cost_for_sorting": 9
"estimated_join_cardinality": 9
} }
] ]
}, },
...@@ -2140,8 +2129,7 @@ explain select * from t1 where a=1 and b=2 order by c limit 1 { ...@@ -2140,8 +2129,7 @@ explain select * from t1 where a=1 and b=2 order by c limit 1 {
} }
}, },
"rows_for_plan": 21, "rows_for_plan": 21,
"cost_for_plan": 25.34242739, "cost_for_plan": 25.34242739
"estimated_join_cardinality": 21
} }
] ]
}, },
...@@ -2392,8 +2380,7 @@ select t1.a from t1 left join t2 on t1.a=t2.a { ...@@ -2392,8 +2380,7 @@ select t1.a from t1 left join t2 on t1.a=t2.a {
} }
}, },
"rows_for_plan": 4, "rows_for_plan": 4,
"cost_for_plan": 2.806835937, "cost_for_plan": 2.806835937
"estimated_join_cardinality": 4
} }
] ]
}, },
...@@ -2561,7 +2548,7 @@ explain select * from t1 left join t2 on t2.a=t1.a { ...@@ -2561,7 +2548,7 @@ explain select * from t1 left join t2 on t2.a=t1.a {
}, },
"rows_for_plan": 4, "rows_for_plan": 4,
"cost_for_plan": 7.606835937, "cost_for_plan": 7.606835937,
"estimated_join_cardinality": 4 "pruned_by_hanging_leaf": true
} }
] ]
} }
...@@ -2740,8 +2727,7 @@ explain select t1.a from t1 left join (t2 join t3 on t2.b=t3.b) on t2.a=t1.a and ...@@ -2740,8 +2727,7 @@ explain select t1.a from t1 left join (t2 join t3 on t2.b=t3.b) on t2.a=t1.a and
} }
}, },
"rows_for_plan": 4, "rows_for_plan": 4,
"cost_for_plan": 2.806835937, "cost_for_plan": 2.806835937
"estimated_join_cardinality": 4
} }
] ]
}, },
...@@ -2948,8 +2934,7 @@ explain extended select * from t1 where a in (select pk from t10) { ...@@ -2948,8 +2934,7 @@ explain extended select * from t1 where a in (select pk from t10) {
} }
}, },
"rows_for_plan": 10, "rows_for_plan": 10,
"cost_for_plan": 4.021972656, "cost_for_plan": 4.021972656
"estimated_join_cardinality": 10
} }
] ]
} }
...@@ -3021,8 +3006,7 @@ explain extended select * from t1 where a in (select pk from t10) { ...@@ -3021,8 +3006,7 @@ explain extended select * from t1 where a in (select pk from t10) {
{ {
"chosen_strategy": "SJ-Materialization" "chosen_strategy": "SJ-Materialization"
} }
], ]
"estimated_join_cardinality": 3
} }
] ]
}, },
...@@ -3427,7 +3411,7 @@ explain select * from t1 where pk = 2 and a=5 and b=1 { ...@@ -3427,7 +3411,7 @@ explain select * from t1 where pk = 2 and a=5 and b=1 {
}, },
"rows_for_plan": 1, "rows_for_plan": 1,
"cost_for_plan": 0.326073957, "cost_for_plan": 0.326073957,
"estimated_join_cardinality": 1 "pruned_by_hanging_leaf": true
} }
] ]
}, },
...@@ -3555,8 +3539,7 @@ select f1(a) from t1 { ...@@ -3555,8 +3539,7 @@ select f1(a) from t1 {
} }
}, },
"rows_for_plan": 4, "rows_for_plan": 4,
"cost_for_plan": 2.806835937, "cost_for_plan": 2.806835937
"estimated_join_cardinality": 4
} }
] ]
}, },
...@@ -3652,8 +3635,7 @@ select f2(a) from t1 { ...@@ -3652,8 +3635,7 @@ select f2(a) from t1 {
} }
}, },
"rows_for_plan": 4, "rows_for_plan": 4,
"cost_for_plan": 2.806835937, "cost_for_plan": 2.806835937
"estimated_join_cardinality": 4
} }
] ]
}, },
...@@ -3699,7 +3681,7 @@ a ...@@ -3699,7 +3681,7 @@ a
2 2
select length(trace) from INFORMATION_SCHEMA.OPTIMIZER_TRACE; select length(trace) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
length(trace) length(trace)
2141 2092
set optimizer_trace_max_mem_size=100; set optimizer_trace_max_mem_size=100;
select * from t1; select * from t1;
a a
...@@ -3713,7 +3695,7 @@ select * from t1 { ...@@ -3713,7 +3695,7 @@ select * from t1 {
"join_preparation": { "join_preparation": {
"select_id": 1, "select_id": 1,
"steps": [ "steps": [
2041 0 1992 0
set optimizer_trace_max_mem_size=0; set optimizer_trace_max_mem_size=0;
select * from t1; select * from t1;
a a
...@@ -3721,7 +3703,7 @@ a ...@@ -3721,7 +3703,7 @@ a
2 2
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE; select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select * from t1 2141 0 select * from t1 2092 0
drop table t1; drop table t1;
set optimizer_trace='enabled=off'; set optimizer_trace='enabled=off';
set @@optimizer_trace_max_mem_size= @save_optimizer_trace_max_mem_size; set @@optimizer_trace_max_mem_size= @save_optimizer_trace_max_mem_size;
...@@ -4064,7 +4046,7 @@ explain delete t0,t1 from t0, t1 where t0.a=t1.a and t1.a<3 { ...@@ -4064,7 +4046,7 @@ explain delete t0,t1 from t0, t1 where t0.a=t1.a and t1.a<3 {
}, },
"rows_for_plan": 3, "rows_for_plan": 3,
"cost_for_plan": 4.948514767, "cost_for_plan": 4.948514767,
"estimated_join_cardinality": 3 "pruned_by_hanging_leaf": true
} }
] ]
}, },
...@@ -4263,8 +4245,7 @@ explain select * from (select rand() from t1)q { ...@@ -4263,8 +4245,7 @@ explain select * from (select rand() from t1)q {
} }
}, },
"rows_for_plan": 3, "rows_for_plan": 3,
"cost_for_plan": 2.605126953, "cost_for_plan": 2.605126953
"estimated_join_cardinality": 3
} }
] ]
}, },
...@@ -4328,8 +4309,7 @@ explain select * from (select rand() from t1)q { ...@@ -4328,8 +4309,7 @@ explain select * from (select rand() from t1)q {
} }
}, },
"rows_for_plan": 3, "rows_for_plan": 3,
"cost_for_plan": 3.6, "cost_for_plan": 3.6
"estimated_join_cardinality": 3
} }
] ]
}, },
...@@ -4557,8 +4537,7 @@ explain select * from t1 where a in (select t_inner_1.a from t1 t_inner_1, t1 t_ ...@@ -4557,8 +4537,7 @@ explain select * from t1 where a in (select t_inner_1.a from t1 t_inner_1, t1 t_
} }
}, },
"rows_for_plan": 9, "rows_for_plan": 9,
"cost_for_plan": 6.410253906, "cost_for_plan": 6.410253906
"estimated_join_cardinality": 9
} }
] ]
}, },
...@@ -4678,8 +4657,7 @@ explain select * from t1 where a in (select t_inner_1.a from t1 t_inner_1, t1 t_ ...@@ -4678,8 +4657,7 @@ explain select * from t1 where a in (select t_inner_1.a from t1 t_inner_1, t1 t_
{ {
"chosen_strategy": "SJ-Materialization" "chosen_strategy": "SJ-Materialization"
} }
], ]
"estimated_join_cardinality": 3
} }
] ]
}, },
...@@ -5222,8 +5200,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) { ...@@ -5222,8 +5200,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
{ {
"chosen_strategy": "DuplicateWeedout" "chosen_strategy": "DuplicateWeedout"
} }
], ]
"estimated_join_cardinality": 27
} }
] ]
}, },
...@@ -5345,8 +5322,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) { ...@@ -5345,8 +5322,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
{ {
"chosen_strategy": "DuplicateWeedout" "chosen_strategy": "DuplicateWeedout"
} }
], ]
"estimated_join_cardinality": 27
} }
] ]
}, },
...@@ -6667,8 +6643,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) { ...@@ -6667,8 +6643,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
} }
}, },
"rows_for_plan": 27, "rows_for_plan": 27,
"cost_for_plan": 10.02050781, "cost_for_plan": 10.02050781
"estimated_join_cardinality": 27
} }
] ]
}, },
...@@ -6741,8 +6716,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) { ...@@ -6741,8 +6716,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
} }
}, },
"rows_for_plan": 27, "rows_for_plan": 27,
"cost_for_plan": 10.02050781, "cost_for_plan": 10.02050781
"estimated_join_cardinality": 27
} }
] ]
}, },
...@@ -6961,8 +6935,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) { ...@@ -6961,8 +6935,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
{ {
"chosen_strategy": "SJ-Materialization" "chosen_strategy": "SJ-Materialization"
} }
], ]
"estimated_join_cardinality": 27
} }
] ]
}, },
...@@ -8124,8 +8097,7 @@ JSON_DETAILED(JSON_EXTRACT(trace, '$**.considered_execution_plans')) ...@@ -8124,8 +8097,7 @@ JSON_DETAILED(JSON_EXTRACT(trace, '$**.considered_execution_plans'))
} }
}, },
"rows_for_plan": 4777.832031, "rows_for_plan": 4777.832031,
"cost_for_plan": 1216.438354, "cost_for_plan": 1216.438354
"estimated_join_cardinality": 4777.832031
} }
] ]
}, },
...@@ -8466,7 +8438,7 @@ JSON_DETAILED(JSON_EXTRACT(trace, '$**.considered_execution_plans')) ...@@ -8466,7 +8438,7 @@ JSON_DETAILED(JSON_EXTRACT(trace, '$**.considered_execution_plans'))
"rows_for_plan": 10, "rows_for_plan": 10,
"cost_for_plan": 26.0278306, "cost_for_plan": 26.0278306,
"cost_for_sorting": 10, "cost_for_sorting": 10,
"estimated_join_cardinality": 10 "pruned_by_hanging_leaf": true
} }
] ]
}, },
...@@ -8786,8 +8758,7 @@ select count(*) from seq_1_to_10000000 { ...@@ -8786,8 +8758,7 @@ select count(*) from seq_1_to_10000000 {
} }
}, },
"rows_for_plan": 10000000, "rows_for_plan": 10000000,
"cost_for_plan": 12000000, "cost_for_plan": 12000000
"estimated_join_cardinality": 10000000
} }
] ]
}, },
...@@ -9202,8 +9173,7 @@ json_detailed(json_extract(trace, '$**.choose_best_splitting')) ...@@ -9202,8 +9173,7 @@ json_detailed(json_extract(trace, '$**.choose_best_splitting'))
}, },
"rows_for_plan": 1.8367, "rows_for_plan": 1.8367,
"cost_for_plan": 2.367925794, "cost_for_plan": 2.367925794,
"cost_for_sorting": 1.8367, "cost_for_sorting": 1.8367
"estimated_join_cardinality": 1.8367
} }
] ]
}, },
......
...@@ -221,8 +221,7 @@ explain select * from t1 where a=1 or b=1 { ...@@ -221,8 +221,7 @@ explain select * from t1 where a=1 or b=1 {
} }
}, },
"rows_for_plan": 2, "rows_for_plan": 2,
"cost_for_plan": 2.884903732, "cost_for_plan": 2.884903732
"estimated_join_cardinality": 2
} }
] ]
}, },
......
...@@ -227,7 +227,7 @@ explain select * from t1 where pk1 != 0 and key1 = 1 { ...@@ -227,7 +227,7 @@ explain select * from t1 where pk1 != 0 and key1 = 1 {
}, },
"rows_for_plan": 1, "rows_for_plan": 1,
"cost_for_plan": 1.325146475, "cost_for_plan": 1.325146475,
"estimated_join_cardinality": 1 "pruned_by_hanging_leaf": true
} }
] ]
}, },
......
...@@ -107,8 +107,7 @@ select * from db1.t1 { ...@@ -107,8 +107,7 @@ select * from db1.t1 {
} }
}, },
"rows_for_plan": 3, "rows_for_plan": 3,
"cost_for_plan": 2.605126953, "cost_for_plan": 2.605126953
"estimated_join_cardinality": 3
} }
] ]
}, },
...@@ -229,8 +228,7 @@ select * from db1.v1 { ...@@ -229,8 +228,7 @@ select * from db1.v1 {
} }
}, },
"rows_for_plan": 3, "rows_for_plan": 3,
"cost_for_plan": 2.605126953, "cost_for_plan": 2.605126953
"estimated_join_cardinality": 3
} }
] ]
}, },
......
...@@ -466,11 +466,11 @@ where t0.a in ( select t1.a from t1,t2 where t2.a=t0.a and ...@@ -466,11 +466,11 @@ where t0.a in ( select t1.a from t1,t2 where t2.a=t0.a and
t1.b=t2.b); t1.b=t2.b);
id select_type table type possible_keys key key_len ref rows filtered Extra id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t0 ALL NULL NULL NULL NULL 5 100.00 Using where 1 PRIMARY t0 ALL NULL NULL NULL NULL 5 100.00 Using where
1 PRIMARY t2 eq_ref PRIMARY PRIMARY 4 test.t0.a 1 100.00 1 PRIMARY t1 ref a a 5 test.t0.a 1 100.00 Start temporary
1 PRIMARY t1 ref a a 5 test.t0.a 1 100.00 Using where; FirstMatch(t2) 1 PRIMARY t2 eq_ref PRIMARY PRIMARY 4 test.t0.a 1 100.00 Using where; End temporary
Warnings: Warnings:
Note 1276 Field or reference 'test.t0.a' of SELECT #2 was resolved in SELECT #1 Note 1276 Field or reference 'test.t0.a' of SELECT #2 was resolved in SELECT #1
Note 1003 select `test`.`t0`.`a` AS `a` from `test`.`t2` semi join (`test`.`t1`) join `test`.`t0` where `test`.`t2`.`a` = `test`.`t0`.`a` and `test`.`t1`.`a` = `test`.`t0`.`a` and `test`.`t1`.`b` = `test`.`t2`.`b` Note 1003 select `test`.`t0`.`a` AS `a` from `test`.`t2` semi join (`test`.`t1`) join `test`.`t0` where `test`.`t1`.`a` = `test`.`t0`.`a` and `test`.`t2`.`a` = `test`.`t0`.`a` and `test`.`t2`.`b` = `test`.`t1`.`b`
update t1 set a=3, b=11 where a=4; update t1 set a=3, b=11 where a=4;
update t2 set b=11 where a=3; update t2 set b=11 where a=3;
select * from t0 where t0.a in select * from t0 where t0.a in
......
...@@ -477,11 +477,11 @@ where t0.a in ( select t1.a from t1,t2 where t2.a=t0.a and ...@@ -477,11 +477,11 @@ where t0.a in ( select t1.a from t1,t2 where t2.a=t0.a and
t1.b=t2.b); t1.b=t2.b);
id select_type table type possible_keys key key_len ref rows filtered Extra id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t0 ALL NULL NULL NULL NULL 5 100.00 Using where 1 PRIMARY t0 ALL NULL NULL NULL NULL 5 100.00 Using where
1 PRIMARY t2 eq_ref PRIMARY PRIMARY 4 test.t0.a 1 100.00 Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan 1 PRIMARY t1 ref a a 5 test.t0.a 1 100.00 Start temporary; Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan
1 PRIMARY t1 ref a a 5 test.t0.a 1 100.00 Using where; FirstMatch(t2); Using join buffer (incremental, BKA join); Key-ordered Rowid-ordered scan 1 PRIMARY t2 eq_ref PRIMARY PRIMARY 4 test.t0.a 1 100.00 Using where; End temporary; Using join buffer (incremental, BKA join); Key-ordered Rowid-ordered scan
Warnings: Warnings:
Note 1276 Field or reference 'test.t0.a' of SELECT #2 was resolved in SELECT #1 Note 1276 Field or reference 'test.t0.a' of SELECT #2 was resolved in SELECT #1
Note 1003 select `test`.`t0`.`a` AS `a` from `test`.`t2` semi join (`test`.`t1`) join `test`.`t0` where `test`.`t2`.`a` = `test`.`t0`.`a` and `test`.`t1`.`a` = `test`.`t0`.`a` and `test`.`t1`.`b` = `test`.`t2`.`b` Note 1003 select `test`.`t0`.`a` AS `a` from `test`.`t2` semi join (`test`.`t1`) join `test`.`t0` where `test`.`t1`.`a` = `test`.`t0`.`a` and `test`.`t2`.`a` = `test`.`t0`.`a` and `test`.`t2`.`b` = `test`.`t1`.`b`
update t1 set a=3, b=11 where a=4; update t1 set a=3, b=11 where a=4;
update t2 set b=11 where a=3; update t2 set b=11 where a=3;
# Not anymore: # Not anymore:
......
...@@ -468,11 +468,11 @@ where t0.a in ( select t1.a from t1,t2 where t2.a=t0.a and ...@@ -468,11 +468,11 @@ where t0.a in ( select t1.a from t1,t2 where t2.a=t0.a and
t1.b=t2.b); t1.b=t2.b);
id select_type table type possible_keys key key_len ref rows filtered Extra id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t0 ALL NULL NULL NULL NULL 5 100.00 Using where 1 PRIMARY t0 ALL NULL NULL NULL NULL 5 100.00 Using where
1 PRIMARY t2 eq_ref PRIMARY PRIMARY 4 test.t0.a 1 100.00 1 PRIMARY t1 ref a a 5 test.t0.a 1 100.00 Start temporary
1 PRIMARY t1 ref a a 5 test.t0.a 1 100.00 Using where; FirstMatch(t2) 1 PRIMARY t2 eq_ref PRIMARY PRIMARY 4 test.t0.a 1 100.00 Using where; End temporary
Warnings: Warnings:
Note 1276 Field or reference 'test.t0.a' of SELECT #2 was resolved in SELECT #1 Note 1276 Field or reference 'test.t0.a' of SELECT #2 was resolved in SELECT #1
Note 1003 select `test`.`t0`.`a` AS `a` from `test`.`t2` semi join (`test`.`t1`) join `test`.`t0` where `test`.`t2`.`a` = `test`.`t0`.`a` and `test`.`t1`.`a` = `test`.`t0`.`a` and `test`.`t1`.`b` = `test`.`t2`.`b` Note 1003 select `test`.`t0`.`a` AS `a` from `test`.`t2` semi join (`test`.`t1`) join `test`.`t0` where `test`.`t1`.`a` = `test`.`t0`.`a` and `test`.`t2`.`a` = `test`.`t0`.`a` and `test`.`t2`.`b` = `test`.`t1`.`b`
update t1 set a=3, b=11 where a=4; update t1 set a=3, b=11 where a=4;
update t2 set b=11 where a=3; update t2 set b=11 where a=3;
select * from t0 where t0.a in select * from t0 where t0.a in
......
...@@ -111,7 +111,14 @@ static void optimize_straight_join(JOIN *join, table_map join_tables); ...@@ -111,7 +111,14 @@ static void optimize_straight_join(JOIN *join, table_map join_tables);
static bool greedy_search(JOIN *join, table_map remaining_tables, static bool greedy_search(JOIN *join, table_map remaining_tables,
uint depth, uint prune_level, uint depth, uint prune_level,
uint use_cond_selectivity); uint use_cond_selectivity);
static bool best_extension_by_limited_search(JOIN *join, enum enum_best_search {
SEARCH_ABORT= -2,
SEARCH_ERROR= -1,
SEARCH_OK= 0,
SEARCH_FOUND_EDGE=1
};
static enum_best_search
best_extension_by_limited_search(JOIN *join,
table_map remaining_tables, table_map remaining_tables,
uint idx, double record_count, uint idx, double record_count,
double read_time, uint depth, double read_time, uint depth,
...@@ -8446,6 +8453,7 @@ best_access_path(JOIN *join, ...@@ -8446,6 +8453,7 @@ best_access_path(JOIN *join,
pos->records_read= records; pos->records_read= records;
pos->read_time= best; pos->read_time= best;
pos->key= best_key; pos->key= best_key;
pos->type= best_type;
pos->table= s; pos->table= s;
pos->ref_depend_map= best_ref_depends_map; pos->ref_depend_map= best_ref_depends_map;
pos->loosescan_picker.loosescan_key= MAX_KEY; pos->loosescan_picker.loosescan_key= MAX_KEY;
...@@ -9101,9 +9109,12 @@ greedy_search(JOIN *join, ...@@ -9101,9 +9109,12 @@ greedy_search(JOIN *join,
do { do {
/* Find the extension of the current QEP with the lowest cost */ /* Find the extension of the current QEP with the lowest cost */
join->best_read= DBL_MAX; join->best_read= DBL_MAX;
if (best_extension_by_limited_search(join, remaining_tables, idx, record_count, if ((int) best_extension_by_limited_search(join, remaining_tables, idx,
read_time, search_depth, prune_level, record_count,
use_cond_selectivity)) read_time, search_depth,
prune_level,
use_cond_selectivity) <
(int) SEARCH_OK)
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
/* /*
'best_read < DBL_MAX' means that optimizer managed to find 'best_read < DBL_MAX' means that optimizer managed to find
...@@ -9739,6 +9750,28 @@ double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s, ...@@ -9739,6 +9750,28 @@ double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s,
} }
/*
Check if the table is an EQ_REF or similar table and there is no cost
to gain by moveing it to a later stage.
We call such a table a edge table (or hanging leaf) as it will read at
most one row and will not add to the number of row combinations in the join.
*/
static inline enum_best_search
check_if_edge_table(POSITION *pos,
double pushdown_cond_selectivity)
{
if ((pos->type == JT_EQ_REF ||
(pos->type == JT_REF &&
pos->records_read == 1 &&
!pos->range_rowid_filter_info)) &&
pushdown_cond_selectivity >= 0.999)
return SEARCH_FOUND_EDGE;
return SEARCH_OK;
}
/** /**
Find a good, possibly optimal, query execution plan (QEP) by a possibly Find a good, possibly optimal, query execution plan (QEP) by a possibly
exhaustive search. exhaustive search.
...@@ -9853,12 +9886,17 @@ double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s, ...@@ -9853,12 +9886,17 @@ double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s,
pushed to a table should be taken into account pushed to a table should be taken into account
@retval @retval
FALSE ok enum_best_search::SEARCH_OK All fine
@retval @retval
TRUE Fatal error enum_best_search::SEARCH_FOUND_EDGE All remaning tables are edge tables
@retval
enum_best_search::SEARCH_ABORT Killed by user
@retval
enum_best_search::SEARCH_ERROR Fatal error
*/ */
static bool
static enum_best_search
best_extension_by_limited_search(JOIN *join, best_extension_by_limited_search(JOIN *join,
table_map remaining_tables, table_map remaining_tables,
uint idx, uint idx,
...@@ -9868,9 +9906,17 @@ best_extension_by_limited_search(JOIN *join, ...@@ -9868,9 +9906,17 @@ best_extension_by_limited_search(JOIN *join,
uint prune_level, uint prune_level,
uint use_cond_selectivity) uint use_cond_selectivity)
{ {
DBUG_ENTER("best_extension_by_limited_search");
THD *thd= join->thd; THD *thd= join->thd;
/*
'join' is a partial plan with lower cost than the best plan so far,
so continue expanding it further with the tables in 'remaining_tables'.
*/
JOIN_TAB *s;
double best_record_count= DBL_MAX;
double best_read_time= DBL_MAX;
bool disable_jbuf= join->thd->variables.join_cache_level == 0;
enum_best_search best_res;
DBUG_ENTER("best_extension_by_limited_search");
DBUG_EXECUTE_IF("show_explain_probe_best_ext_lim_search", DBUG_EXECUTE_IF("show_explain_probe_best_ext_lim_search",
if (dbug_user_var_equals_int(thd, if (dbug_user_var_equals_int(thd,
...@@ -9880,19 +9926,7 @@ best_extension_by_limited_search(JOIN *join, ...@@ -9880,19 +9926,7 @@ best_extension_by_limited_search(JOIN *join,
); );
if (unlikely(thd->check_killed())) // Abort if (unlikely(thd->check_killed())) // Abort
DBUG_RETURN(TRUE); DBUG_RETURN(SEARCH_ABORT);
DBUG_EXECUTE("opt", print_plan(join, idx, read_time, record_count, idx,
"SOFAR:"););
/*
'join' is a partial plan with lower cost than the best plan so far,
so continue expanding it further with the tables in 'remaining_tables'.
*/
JOIN_TAB *s;
double best_record_count= DBL_MAX;
double best_read_time= DBL_MAX;
bool disable_jbuf= join->thd->variables.join_cache_level == 0;
DBUG_EXECUTE("opt", print_plan(join, idx, record_count, read_time, read_time, DBUG_EXECUTE("opt", print_plan(join, idx, record_count, read_time, read_time,
"part_plan");); "part_plan"););
...@@ -9914,9 +9948,11 @@ best_extension_by_limited_search(JOIN *join, ...@@ -9914,9 +9948,11 @@ best_extension_by_limited_search(JOIN *join,
(!idx || !check_interleaving_with_nj(s))) (!idx || !check_interleaving_with_nj(s)))
{ {
double current_record_count, current_read_time; double current_record_count, current_read_time;
double partial_join_cardinality;
POSITION *position= join->positions + idx; POSITION *position= join->positions + idx;
POSITION loose_scan_pos;
Json_writer_object trace_one_table(thd); Json_writer_object trace_one_table(thd);
if (unlikely(thd->trace_started())) if (unlikely(thd->trace_started()))
{ {
trace_plan_prefix(join, idx, remaining_tables); trace_plan_prefix(join, idx, remaining_tables);
...@@ -9924,7 +9960,6 @@ best_extension_by_limited_search(JOIN *join, ...@@ -9924,7 +9960,6 @@ best_extension_by_limited_search(JOIN *join,
} }
/* Find the best access method from 's' to the current partial plan */ /* Find the best access method from 's' to the current partial plan */
POSITION loose_scan_pos;
best_access_path(join, s, remaining_tables, join->positions, idx, best_access_path(join, s, remaining_tables, join->positions, idx,
disable_jbuf, record_count, position, &loose_scan_pos); disable_jbuf, record_count, position, &loose_scan_pos);
...@@ -10003,28 +10038,47 @@ best_extension_by_limited_search(JOIN *join, ...@@ -10003,28 +10038,47 @@ best_extension_by_limited_search(JOIN *join,
~real_table_bit); ~real_table_bit);
join->positions[idx].cond_selectivity= pushdown_cond_selectivity; join->positions[idx].cond_selectivity= pushdown_cond_selectivity;
if (unlikely(thd->trace_started()) && pushdown_cond_selectivity < 1.0) partial_join_cardinality= (current_record_count *
pushdown_cond_selectivity);
if (unlikely(thd->trace_started()))
{
if (pushdown_cond_selectivity < 1.0)
{
trace_one_table.add("selectivity", pushdown_cond_selectivity); trace_one_table.add("selectivity", pushdown_cond_selectivity);
trace_one_table.add("estimated_join_cardinality",
partial_join_cardinality);
}
}
double partial_join_cardinality= current_record_count * if ((search_depth > 1) && (remaining_tables & ~real_table_bit) &
pushdown_cond_selectivity; allowed_tables)
if ( (search_depth > 1) && (remaining_tables & ~real_table_bit) & allowed_tables ) {
{ /* Recursively expand the current partial plan */ /* Recursively expand the current partial plan */
swap_variables(JOIN_TAB*, join->best_ref[idx], *pos); swap_variables(JOIN_TAB*, join->best_ref[idx], *pos);
Json_writer_array trace_rest(thd, "rest_of_plan"); Json_writer_array trace_rest(thd, "rest_of_plan");
if (best_extension_by_limited_search(join, best_res=
remaining_tables & ~real_table_bit, best_extension_by_limited_search(join,
remaining_tables &
~real_table_bit,
idx + 1, idx + 1,
partial_join_cardinality, partial_join_cardinality,
current_read_time, current_read_time,
search_depth - 1, search_depth - 1,
prune_level, prune_level,
use_cond_selectivity)) use_cond_selectivity);
DBUG_RETURN(TRUE); if ((int) best_res < (int) SEARCH_OK)
DBUG_RETURN(best_res); // Abort
swap_variables(JOIN_TAB*, join->best_ref[idx], *pos); swap_variables(JOIN_TAB*, join->best_ref[idx], *pos);
if (best_res == SEARCH_FOUND_EDGE &&
check_if_edge_table(join->positions+ idx,
pushdown_cond_selectivity) !=
SEARCH_FOUND_EDGE)
best_res= SEARCH_OK;
} }
else else
{ /* {
/*
'join' is either the best partial QEP with 'search_depth' relations, 'join' is either the best partial QEP with 'search_depth' relations,
or the best complete QEP so far, whichever is smaller. or the best complete QEP so far, whichever is smaller.
*/ */
...@@ -10040,8 +10094,6 @@ best_extension_by_limited_search(JOIN *join, ...@@ -10040,8 +10094,6 @@ best_extension_by_limited_search(JOIN *join,
trace_one_table.add("cost_for_sorting", current_record_count); trace_one_table.add("cost_for_sorting", current_record_count);
current_read_time= COST_ADD(current_read_time, current_record_count); current_read_time= COST_ADD(current_read_time, current_record_count);
} }
trace_one_table.add("estimated_join_cardinality",
partial_join_cardinality);
if (current_read_time < join->best_read) if (current_read_time < join->best_read)
{ {
memcpy((uchar*) join->best_positions, (uchar*) join->positions, memcpy((uchar*) join->best_positions, (uchar*) join->positions,
...@@ -10054,12 +10106,19 @@ best_extension_by_limited_search(JOIN *join, ...@@ -10054,12 +10106,19 @@ best_extension_by_limited_search(JOIN *join,
read_time, read_time,
current_read_time, current_read_time,
"full_plan");); "full_plan"););
best_res= check_if_edge_table(join->positions + idx,
pushdown_cond_selectivity);
} }
restore_prev_nj_state(s); restore_prev_nj_state(s);
restore_prev_sj_state(remaining_tables, s, idx); restore_prev_sj_state(remaining_tables, s, idx);
if (best_res == SEARCH_FOUND_EDGE)
{
trace_one_table.add("pruned_by_hanging_leaf", true);
DBUG_RETURN(best_res);
} }
} }
DBUG_RETURN(FALSE); }
DBUG_RETURN(SEARCH_OK);
} }
......
...@@ -989,6 +989,8 @@ class POSITION ...@@ -989,6 +989,8 @@ class POSITION
*/ */
enum sj_strategy_enum sj_strategy; enum sj_strategy_enum sj_strategy;
/* Type of join (EQ_REF, REF etc) */
enum join_type type;
/* /*
Valid only after fix_semijoin_strategies_for_picked_join_order() call: Valid only after fix_semijoin_strategies_for_picked_join_order() call:
if sj_strategy!=SJ_OPT_NONE, this is the number of subsequent tables that if sj_strategy!=SJ_OPT_NONE, this is the number of subsequent tables that
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment