Skip to content

Commit 427ee36

Browse files
committed
Bug#36625968: Long query execution times due to hypergraph optimizer choosing un-indexed NLJ
Query plans with nested loop joins are risky if the inner side of the join cannot use indexes to limit the number of rows to read. Even though they are estimated to be slightly cheaper than the corresponding hash join in some cases, if the row estimates are a little off, the actual cost of executing the join can multiply many times. The performance of hash joins degrades more gracefully when the estimates are off. In order to avoid these risky plans, the hypergraph optimizer is changed so that it proposes nested loop joins only if it can push the join condition to an index lookup on the right hand side of the join. If it doesn't have an index to use for the join condition, only the corresponding hash join is proposed. Exceptions to this are made for cases in which a hash join cannot be used (mainly cases involving full-text search, lateral derived tables or table functions). Also, a nested loop join is allowed if either of the sides is known to return at most one row, in which case a nested loop join should be at least as good as a hash join, and there's no risk of row estimates being far off. Change-Id: Iab22e296a5042a7ac1cce80bacc265c7a2c0b78e
1 parent 8475338 commit 427ee36

File tree

70 files changed

+2262
-1831
lines changed

Some content is hidden

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

70 files changed

+2262
-1831
lines changed

mysql-test/common/binlog/mysqlbinlog_row.inc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -470,12 +470,12 @@ SET sql_mode = default;
470470
# Check multi-table update
471471
#
472472
CREATE TABLE t1 (a int NOT NULL DEFAULT 0, b int NOT NULL DEFAULT 0);
473-
CREATE TABLE t2 (a int NOT NULL DEFAULT 0, b int NOT NULL DEFAULT 0);
473+
CREATE TABLE t2 (a int NOT NULL DEFAULT 0, b int NOT NULL DEFAULT 0, UNIQUE (b));
474474
INSERT INTO t1 SET a=1;
475475
INSERT INTO t1 SET b=1;
476476
INSERT INTO t2 SET a=1;
477477
INSERT INTO t2 SET b=1;
478-
UPDATE t1, t2 SET t1.a=10, t2.a=20;
478+
UPDATE t1, t2 SET t1.a=10, t2.a=20 WHERE t1.b = t2.b;
479479
DROP TABLE t1,t2;
480480

481481

mysql-test/common/rpl/rpl_multi_update3.test

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,13 @@ UPDATE t2, (SELECT a FROM t1 ORDER BY a) AS t SET t2.b = t.a+5 ;
3636
SET @@optimizer_switch=@optimizer_switch_saved;
3737

3838
SELECT * FROM t1 ORDER BY a;
39+
--skip_if_hypergraph # Non-deterministic multi-table update of t2 above.
3940
SELECT * FROM t2 ORDER BY a;
4041

4142
--source include/rpl/sync_to_replica.inc
4243
connection slave;
4344
SELECT * FROM t1 ORDER BY a;
45+
--skip_if_hypergraph # Non-deterministic multi-table update of t2 above.
4446
SELECT * FROM t2 ORDER BY a;
4547

4648
connection master;

mysql-test/include/ctype_utf8mb4.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,7 @@ eval CREATE TABLE t2 (
931931

932932
INSERT INTO t2 VALUES ('1234567890',2,'2005-05-24 13:53:25');
933933

934+
--sorted_result
934935
SELECT content, t2.msisdn FROM t1, t2 WHERE t1.msisdn = '1234567890';
935936

936937
DROP TABLE t1,t2;

mysql-test/include/select.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4220,6 +4220,7 @@ SELECT table4 . `time_nokey` AS field1 FROM
42204220
table1 . `int_nokey` != 'f')
42214221
GROUP BY field1 ORDER BY field1 , field1;
42224222

4223+
--sorted_result
42234224
SELECT table1 .`time_key` field2 FROM B table1 LEFT JOIN BB JOIN A table5 ON table5 .`date_nokey` ON table5 .`int_nokey` GROUP BY field2;
42244225
--enable_warnings
42254226

mysql-test/include/subquery.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2151,6 +2151,7 @@ CREATE TABLE t3 ( c3 integer );
21512151
INSERT INTO t3 VALUES ( 7 );
21522152
INSERT INTO t3 VALUES ( 8 );
21532153

2154+
--sorted_result
21542155
SELECT c1,c2 FROM t1 LEFT JOIN t2 ON c1 = c2
21552156
WHERE EXISTS (SELECT c3 FROM t3 WHERE c2 IS NULL );
21562157

mysql-test/include/subquery_sj.inc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,7 @@ INSERT INTO t3 VALUES (22,'come','h'),
661661
(24,'lpjdzvkp','ababa'),
662662
(25,'d','GGDD');
663663

664+
--sorted_result
664665
SELECT * FROM t1 WHERE (field1, field2) IN (
665666
SELECT table1.col_varchar_255_utf8_key AS field1,
666667
table1.col_varchar_255_utf8_key AS field2
@@ -2905,6 +2906,7 @@ INSERT INTO t1 VALUES(10),(20);
29052906
create table t2 select * from t1;
29062907
create table t3 select * from t1;
29072908

2909+
--sorted_result
29082910
SELECT *
29092911
FROM t1
29102912
WHERE 1 IN(SELECT 1
@@ -4190,6 +4192,7 @@ SELECT * FROM t2
41904192
WHERE f2 IN (SELECT t1.f1
41914193
FROM t1 LEFT OUTER JOIN (t2 AS b1 JOIN t2 AS b2 ON TRUE) ON TRUE);
41924194
eval EXPLAIN $query;
4195+
--sorted_result
41934196
eval $query;
41944197

41954198
DROP TABLE t1, t2;
@@ -4336,7 +4339,14 @@ WHERE col_varchar_10_latin1_key IN (
43364339
WHERE alias1.pk AND alias1.pk < 3 OR alias1.pk AND alias3.pk);
43374340
ANALYZE TABLE t1, t2, t3;
43384341
eval EXPLAIN $query;
4342+
if ($HYPERGRAPH_TEST) {
4343+
# Different warnings with hypergraph than with old optimizer.
4344+
--disable_warnings
4345+
}
43394346
eval $query;
4347+
if ($HYPERGRAPH_TEST) {
4348+
--enable_warnings
4349+
}
43404350

43414351
DROP TABLE t1, t2, t3;
43424352

@@ -5129,6 +5139,7 @@ eval $query;
51295139
ALTER TABLE t1 ENGINE=Innodb;
51305140
ALTER TABLE t2 ENGINE=Innodb;
51315141

5142+
--sorted_result
51325143
eval $query;
51335144

51345145
DROP TABLE t1, t2;

mysql-test/include/with_recursive.inc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,14 @@ select 1 from t1 straight_join qn
338338
)
339339
select * from qn;
340340

341+
WITH RECURSIVE qn(n) AS
342+
(
343+
SELECT 1 FROM t1
344+
UNION ALL
345+
SELECT n+1 FROM qn STRAIGHT_JOIN t1 WHERE n < 3
346+
)
347+
SELECT COUNT(*) FROM qn;
348+
341349
--error ER_CTE_RECURSIVE_FORBIDDEN_JOIN_ORDER
342350
WITH RECURSIVE qn AS
343351
(

mysql-test/r/ctype_utf8mb4_heap.result

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1138,8 +1138,8 @@ UNIQUE KEY `PK_user` (`msisdn`)
11381138
INSERT INTO t2 VALUES ('1234567890',2,'2005-05-24 13:53:25');
11391139
SELECT content, t2.msisdn FROM t1, t2 WHERE t1.msisdn = '1234567890';
11401140
content msisdn
1141-
ERR Имри.Афимим.Аеимимримдмримрмрирор имримримримр имридм ирбднримрфмририримрфмфмим.Ад.Д имдимримрад.Адимримримрмдиримримримр м.Дадимфшьмримд им.Адимимрн имадми 1234567890
11421141
11 g 1234567890
1142+
ERR Имри.Афимим.Аеимимримдмримрмрирор имримримримр имридм ирбднримрфмририримрфмфмим.Ад.Д имдимримрад.Адимримримрмдиримримримр м.Дадимфшьмримд им.Адимимрн имадми 1234567890
11431143
DROP TABLE t1,t2;
11441144
SET sql_mode = default;
11451145
SET sql_mode = 'NO_ENGINE_SUBSTITUTION';

mysql-test/r/ctype_utf8mb4_innodb.result

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1205,8 +1205,8 @@ UNIQUE KEY `PK_user` (`msisdn`)
12051205
INSERT INTO t2 VALUES ('1234567890',2,'2005-05-24 13:53:25');
12061206
SELECT content, t2.msisdn FROM t1, t2 WHERE t1.msisdn = '1234567890';
12071207
content msisdn
1208-
ERR Имри.Афимим.Аеимимримдмримрмрирор имримримримр имридм ирбднримрфмририримрфмфмим.Ад.Д имдимримрад.Адимримримрмдиримримримр м.Дадимфшьмримд им.Адимимрн имадми 1234567890
12091208
11 g 1234567890
1209+
ERR Имри.Афимим.Аеимимримдмримрмрирор имримримримр имридм ирбднримрфмририримрфмфмим.Ад.Д имдимримрад.Адимримримрмдиримримримр м.Дадимфшьмримд им.Адимимрн имадми 1234567890
12101210
DROP TABLE t1,t2;
12111211
SET sql_mode = default;
12121212
SET sql_mode = 'NO_ENGINE_SUBSTITUTION';

mysql-test/r/ctype_utf8mb4_myisam.result

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1205,8 +1205,8 @@ UNIQUE KEY `PK_user` (`msisdn`)
12051205
INSERT INTO t2 VALUES ('1234567890',2,'2005-05-24 13:53:25');
12061206
SELECT content, t2.msisdn FROM t1, t2 WHERE t1.msisdn = '1234567890';
12071207
content msisdn
1208-
ERR Имри.Афимим.Аеимимримдмримрмрирор имримримримр имридм ирбднримрфмририримрфмфмим.Ад.Д имдимримрад.Адимримримрмдиримримримр м.Дадимфшьмримд им.Адимимрн имадми 1234567890
12091208
11 g 1234567890
1209+
ERR Имри.Афимим.Аеимимримдмримрмрирор имримримримр имридм ирбднримрфмририримрфмфмим.Ад.Д имдимримрад.Адимримримрмдиримримримр м.Дадимфшьмримд им.Адимимрн имадми 1234567890
12101210
DROP TABLE t1,t2;
12111211
SET sql_mode = default;
12121212
SET sql_mode = 'NO_ENGINE_SUBSTITUTION';

mysql-test/r/explain_for_schema_hypergraph.result

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,11 @@ EXPLAIN FORMAT=TREE FOR SCHEMA test_explain_for_schema SELECT * FROM t1 JOIN t2
117117
END|
118118
CALL p;
119119
EXPLAIN
120-
-> Nested loop inner join (...)
121-
-> Filter: (t1.i2 = 2) (...)
122-
-> Table scan on t1 (...)
123-
-> Filter: (t1.i1 = t2.i3) (...)
124-
-> Table scan on t2 (...)
120+
-> Inner hash join (t1.i1 = t2.i3) (...)
121+
-> Table scan on t2 (...)
122+
-> Hash
123+
-> Filter: (t1.i2 = 2) (...)
124+
-> Table scan on t1 (...)
125125

126126
DROP PROCEDURE p;
127127
# Check that correct schema is used to qualify functions in an SP

mysql-test/r/explain_into_hypergraph.result

Lines changed: 50 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,19 @@ SELECT @v1, JSON_VALID(@v1);
3838
{
3939
"query": "/* select#1 */ select `test`.`t1`.`i1` AS `i1`,`test`.`t1`.`i2` AS `i2`,`test`.`t2`.`i3` AS `i3`,`test`.`t2`.`i4` AS `i4` from `test`.`t1` join `test`.`t2` where ((`test`.`t1`.`i2` = 2) and (`test`.`t1`.`i1` = `test`.`t2`.`i3`))",
4040
"inputs": [
41+
{
42+
"operation": "Table scan on t2",
43+
"table_name": "t2",
44+
"access_type": "table",
45+
"schema_name": "test",
46+
"used_columns": [
47+
"i3",
48+
"i4"
49+
],
50+
"estimated_rows": 3.0,
51+
"estimated_total_cost": "elided",
52+
"estimated_first_row_cost": "elided"
53+
},
4154
{
4255
"inputs": [
4356
{
@@ -54,6 +67,7 @@ SELECT @v1, JSON_VALID(@v1);
5467
"estimated_first_row_cost": "elided"
5568
}
5669
],
70+
"heading": "Hash",
5771
"condition": "(t1.i2 = 2)",
5872
"operation": "Filter: (t1.i2 = 2)",
5973
"access_type": "filter",
@@ -63,41 +77,21 @@ SELECT @v1, JSON_VALID(@v1);
6377
],
6478
"estimated_total_cost": "elided",
6579
"estimated_first_row_cost": "elided"
66-
},
67-
{
68-
"inputs": [
69-
{
70-
"operation": "Table scan on t2",
71-
"table_name": "t2",
72-
"access_type": "table",
73-
"schema_name": "test",
74-
"used_columns": [
75-
"i3",
76-
"i4"
77-
],
78-
"estimated_rows": 3.0,
79-
"estimated_total_cost": "elided",
80-
"estimated_first_row_cost": "elided"
81-
}
82-
],
83-
"condition": "(t1.i1 = t2.i3)",
84-
"operation": "Filter: (t1.i1 = t2.i3)",
85-
"access_type": "filter",
86-
"estimated_rows": 1.0,
87-
"filter_columns": [
88-
"test.t1.i1",
89-
"test.t2.i3"
90-
],
91-
"estimated_total_cost": "elided",
92-
"estimated_first_row_cost": "elided"
9380
}
9481
],
9582
"join_type": "inner join",
96-
"operation": "Nested loop inner join",
83+
"operation": "Inner hash join (t1.i1 = t2.i3)",
9784
"query_type": "select",
9885
"access_type": "join",
86+
"join_columns": [
87+
"test.t1.i1",
88+
"test.t2.i3"
89+
],
9990
"estimated_rows": 0.30000000447034836,
100-
"join_algorithm": "nested_loop",
91+
"hash_condition": [
92+
"(t1.i1 = t2.i3)"
93+
],
94+
"join_algorithm": "hash",
10195
"estimated_total_cost": "elided",
10296
"estimated_first_row_cost": "elided"
10397
} 1
@@ -172,6 +166,23 @@ SELECT @v1, JSON_VALID(@v1);
172166
{
173167
"query": "/* select#1 */ select `test`.`t1`.`i1` AS `i1`,`test`.`t1`.`i2` AS `i2`,`test`.`t2`.`i3` AS `i3`,`test`.`t2`.`i4` AS `i4` from `test`.`t1` join `test`.`t2` where ((`test`.`t1`.`i2` = 2) and (`test`.`t1`.`i1` = `test`.`t2`.`i3`))",
174168
"inputs": [
169+
{
170+
"operation": "Table scan on t2",
171+
"table_name": "t2",
172+
"access_type": "table",
173+
"actual_rows": 3.0,
174+
"schema_name": "test",
175+
"actual_loops": 1,
176+
"used_columns": [
177+
"i3",
178+
"i4"
179+
],
180+
"estimated_rows": 3.0,
181+
"actual_last_row_ms": "elided",
182+
"actual_first_row_ms": "elided",
183+
"estimated_total_cost": "elided",
184+
"estimated_first_row_cost": "elided"
185+
},
175186
{
176187
"inputs": [
177188
{
@@ -192,6 +203,7 @@ SELECT @v1, JSON_VALID(@v1);
192203
"estimated_first_row_cost": "elided"
193204
}
194205
],
206+
"heading": "Hash",
195207
"condition": "(t1.i2 = 2)",
196208
"operation": "Filter: (t1.i2 = 2)",
197209
"access_type": "filter",
@@ -205,51 +217,23 @@ SELECT @v1, JSON_VALID(@v1);
205217
"actual_first_row_ms": "elided",
206218
"estimated_total_cost": "elided",
207219
"estimated_first_row_cost": "elided"
208-
},
209-
{
210-
"inputs": [
211-
{
212-
"operation": "Table scan on t2",
213-
"table_name": "t2",
214-
"access_type": "table",
215-
"actual_rows": 3.0,
216-
"schema_name": "test",
217-
"actual_loops": 1,
218-
"used_columns": [
219-
"i3",
220-
"i4"
221-
],
222-
"estimated_rows": 3.0,
223-
"actual_last_row_ms": "elided",
224-
"actual_first_row_ms": "elided",
225-
"estimated_total_cost": "elided",
226-
"estimated_first_row_cost": "elided"
227-
}
228-
],
229-
"condition": "(t1.i1 = t2.i3)",
230-
"operation": "Filter: (t1.i1 = t2.i3)",
231-
"access_type": "filter",
232-
"actual_rows": 0.0,
233-
"actual_loops": 1,
234-
"estimated_rows": 1.0,
235-
"filter_columns": [
236-
"test.t1.i1",
237-
"test.t2.i3"
238-
],
239-
"actual_last_row_ms": "elided",
240-
"actual_first_row_ms": "elided",
241-
"estimated_total_cost": "elided",
242-
"estimated_first_row_cost": "elided"
243220
}
244221
],
245222
"join_type": "inner join",
246-
"operation": "Nested loop inner join",
223+
"operation": "Inner hash join (t1.i1 = t2.i3)",
247224
"query_type": "select",
248225
"access_type": "join",
249226
"actual_rows": 0.0,
250227
"actual_loops": 1,
228+
"join_columns": [
229+
"test.t1.i1",
230+
"test.t2.i3"
231+
],
251232
"estimated_rows": 0.30000000447034836,
252-
"join_algorithm": "nested_loop",
233+
"hash_condition": [
234+
"(t1.i1 = t2.i3)"
235+
],
236+
"join_algorithm": "hash",
253237
"actual_last_row_ms": "elided",
254238
"actual_first_row_ms": "elided",
255239
"estimated_total_cost": "elided",

0 commit comments

Comments
 (0)