From 349f5bf2dacd84470a6284443cdf9f0563c0930c Mon Sep 17 00:00:00 2001 From: Oleg Smirnov Date: Thu, 30 Jan 2025 20:56:36 +0700 Subject: [PATCH] MDEV-34870: implement join order hints This commit implements optimizer hints allowing to affect the order of joining tables: - JOIN_FIXED_ORDER similar to existing STRAIGHT_JOIN hint; - JOIN_ORDER to apply the specified table order; - JOIN_PREFIX to hint what tables should be first in the join; - JOIN_SUFFIX to hint what tables should be last in the join. --- mysql-test/main/lowercase_table.result | 2 +- mysql-test/main/opt_hint_timeout.result | 4 +- mysql-test/main/opt_hints.result | 76 +- mysql-test/main/opt_hints_join_order.result | 1326 +++++++++++++++++ mysql-test/main/opt_hints_join_order.test | 791 ++++++++++ mysql-test/main/opt_hints_subquery.result | 88 +- mysql-test/main/opt_trace.result | 872 +++++------ mysql-test/main/opt_trace_index_merge.result | 20 +- .../main/opt_trace_index_merge_innodb.result | 20 +- mysql-test/main/opt_trace_security.result | 40 +- sql/opt_hints.cc | 956 +++++------- sql/opt_hints.h | 132 +- sql/opt_hints_parser.cc | 843 ++++++++++- sql/opt_hints_parser.h | 114 +- sql/share/errmsg-utf8.txt | 2 + sql/simple_parser.h | 30 +- sql/sql_select.cc | 184 ++- sql/sql_select.h | 9 +- 18 files changed, 4198 insertions(+), 1311 deletions(-) create mode 100644 mysql-test/main/opt_hints_join_order.result create mode 100644 mysql-test/main/opt_hints_join_order.test diff --git a/mysql-test/main/lowercase_table.result b/mysql-test/main/lowercase_table.result index add0fd1f3a6..eaeb495aa84 100644 --- a/mysql-test/main/lowercase_table.result +++ b/mysql-test/main/lowercase_table.result @@ -230,7 +230,7 @@ a 1 2 Warnings: -Warning 4207 Hint BKA("A") is ignored as conflicting/duplicated +Warning 4210 Hint BKA("A") is ignored as conflicting/duplicated DROP TABLE t1; # # End of 11.7 tests diff --git a/mysql-test/main/opt_hint_timeout.result b/mysql-test/main/opt_hint_timeout.result index 7bc1d73a3e5..2eb86462d18 100644 --- a/mysql-test/main/opt_hint_timeout.result +++ b/mysql-test/main/opt_hint_timeout.result @@ -49,7 +49,7 @@ SELECT /*+ MAX_EXECUTION_TIME(10) MAX_EXECUTION_TIME(100) */ count(*) FROM t1; count(*) 512 Warnings: -Warning 4207 Hint MAX_EXECUTION_TIME(100) is ignored as conflicting/duplicated +Warning 4210 Hint MAX_EXECUTION_TIME(100) is ignored as conflicting/duplicated # Wrong values SELECT /*+ MAX_EXECUTION_TIME(0) */ count(*) FROM t1; count(*) @@ -102,7 +102,7 @@ SELECT /*+ MAX_EXECUTION_TIME(30) */ count(*) FROM t1; count(*) 512 Warnings: -Warning 4207 Hint MAX_EXECUTION_TIME(30) is ignored as conflicting/duplicated +Warning 4210 Hint MAX_EXECUTION_TIME(30) is ignored as conflicting/duplicated SELECT count(*) FROM t1 UNION SELECT /*+ MAX_EXECUTION_TIME(30) */ count(*) FROM t1; diff --git a/mysql-test/main/opt_hints.result b/mysql-test/main/opt_hints.result index c5abba7fe04..6442cb62347 100644 --- a/mysql-test/main/opt_hints.result +++ b/mysql-test/main/opt_hints.result @@ -15,25 +15,25 @@ a 1 2 Warnings: -Warning 4210 Unresolved index name `t1`@`select#1` `idx_å` for NO_MRR hint +Warning 4213 Unresolved index name `t1`@`select#1` `idx_å` for NO_MRR hint SELECT /*+ NO_MRR(t1 idx_a, idx_å, idx_A) */ a FROM t1; a 1 2 Warnings: -Warning 4207 Hint NO_MRR(`t1` `idx_A`) is ignored as conflicting/duplicated -Warning 4210 Unresolved index name `t1`@`select#1` `idx_å` for NO_MRR hint +Warning 4210 Hint NO_MRR(`t1` `idx_A`) is ignored as conflicting/duplicated +Warning 4213 Unresolved index name `t1`@`select#1` `idx_å` for NO_MRR hint DROP TABLE t1; # Testing that query block names are accent sensitive case insensitive CREATE TABLE t1 (a INT); SELECT /*+ QB_NAME(a) BKA(t1@a) BKA(t1@A) */ * FROM t1; a Warnings: -Warning 4207 Hint BKA(`t1`@`A`) is ignored as conflicting/duplicated +Warning 4210 Hint BKA(`t1`@`A`) is ignored as conflicting/duplicated SELECT /*+ QB_NAME(a) BKA(t1@a) BKA(t1@å) */ * FROM t1; a Warnings: -Warning 4208 Query block name `å` is not found for BKA hint +Warning 4211 Query block name `å` is not found for BKA hint DROP TABLE t1; CREATE TABLE t1(f1 INT, f2 INT); INSERT INTO t1 VALUES @@ -230,7 +230,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t4 ref y_idx y_idx 5 const 1 100.00 1 SIMPLE t5 range x_idx x_idx 5 NULL 2 100.00 Using where; Using join buffer (flat, BNL join) Warnings: -Warning 4210 Unresolved index name `t5`@`select#2` `z_idx` for NO_ICP hint +Warning 4213 Unresolved index name `t5`@`select#2` `z_idx` for NO_ICP hint Note 1003 select /*+ NO_ICP(`t5`@`select#2` `y_idx`) NO_ICP(`t5`@`select#2` `x_idx`) */ `test`.`t4`.`x` AS `x`,`test`.`t5`.`y` AS `y` from `test`.`t4` join `test`.`t4` `t5` where `test`.`t4`.`y` = 8 and `test`.`t5`.`x` between 7 and (8 + 0) # ICP should still be used EXPLAIN EXTENDED SELECT * FROM @@ -548,7 +548,7 @@ EXPLAIN EXTENDED SELECT /*+ QB_NAME(qb1) QB_NAME(qb1 ) */ * FROM t2; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 28 100.00 Warnings: -Warning 4207 Hint QB_NAME(`qb1`) is ignored as conflicting/duplicated +Warning 4210 Hint QB_NAME(`qb1`) is ignored as conflicting/duplicated Note 1003 select /*+ QB_NAME(`qb1`) */ `test`.`t2`.`f1` AS `f1`,`test`.`t2`.`f2` AS `f2`,`test`.`t2`.`f3` AS `f3` from `test`.`t2` # Should issue warning EXPLAIN EXTENDED SELECT /*+ BKA(@qb1) QB_NAME(qb1) */ t2.f1, t2.f2, t2.f3 FROM t1,t2 @@ -557,7 +557,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 1 SIMPLE t2 ALL f1 NULL NULL NULL 28 25.00 Using where; Using join buffer (flat, BNL join) Warnings: -Warning 4208 Query block name `qb1` is not found for BKA hint +Warning 4211 Query block name `qb1` is not found for BKA hint Note 1003 select /*+ QB_NAME(`qb1`) */ `test`.`t2`.`f1` AS `f1`,`test`.`t2`.`f2` AS `f2`,`test`.`t2`.`f3` AS `f3` from `test`.`t1` join `test`.`t2` where `test`.`t2`.`f1` = `test`.`t1`.`f1` and `test`.`t2`.`f2` between `test`.`t1`.`f1` and `test`.`t1`.`f2` and `test`.`t2`.`f2` + 1 >= `test`.`t1`.`f1` + 1 # Should not crash PREPARE stmt1 FROM "SELECT /*+ BKA(t2) */ t2.f1, t2.f2, t2.f3 FROM t1,t2 @@ -601,9 +601,9 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 1 SIMPLE t2 ALL f1 NULL NULL NULL 28 25.00 Using where; Using join buffer (flat, BNL join) Warnings: -Warning 4209 Unresolved table name `t3`@`select#1` for BKA hint -Warning 4209 Unresolved table name `t3`@`select#1` for NO_RANGE_OPTIMIZATION hint -Warning 4210 Unresolved index name `t3`@`select#1` `idx1` for NO_RANGE_OPTIMIZATION hint +Warning 4212 Unresolved table name `t3`@`select#1` for BKA hint +Warning 4212 Unresolved table name `t3`@`select#1` for NO_RANGE_OPTIMIZATION hint +Warning 4213 Unresolved index name `t3`@`select#1` `idx1` for NO_RANGE_OPTIMIZATION hint Note 1003 select /*+ BKA(`t2`@`select#1`) NO_BNL(`t1`@`select#1`) */ `test`.`t2`.`f1` AS `f1`,`test`.`t2`.`f2` AS `f2`,`test`.`t2`.`f3` AS `f3` from `test`.`t1` join `test`.`t2` where `test`.`t2`.`f1` = `test`.`t1`.`f1` and `test`.`t2`.`f2` between `test`.`t1`.`f1` and `test`.`t1`.`f2` and `test`.`t2`.`f2` + 1 >= `test`.`t1`.`f1` + 1 # Check illegal syntax EXPLAIN EXTENDED SELECT /*+ BKA(qb1 t3@qb1) */ f2 FROM @@ -640,7 +640,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE tbl12 ALL NULL NULL NULL NULL 10 100.00 Using where 1 SIMPLE tbl13 hash_ALL a #hash#a 5 test.tbl12.a 1000 0.10 Using where; Using join buffer (flat, BNLH join) Warnings: -Warning 4209 Unresolved table name `tbl2`@`select#1` for BKA hint +Warning 4212 Unresolved table name `tbl2`@`select#1` for BKA hint Note 1003 select `test`.`tbl12`.`a` AS `a`,`test`.`tbl12`.`b` AS `b`,`test`.`tbl13`.`a` AS `a`,`test`.`tbl13`.`b` AS `b`,`test`.`tbl13`.`c` AS `c`,`test`.`tbl13`.`filler` AS `filler` from `test`.`t12` `tbl12` join `test`.`t13` `tbl13` where `test`.`tbl13`.`a` = `test`.`tbl12`.`a` and `test`.`tbl13`.`b` + 1 <= `test`.`tbl13`.`b` + 1 # Check that PS and conventional statements give the same result. FLUSH STATUS; @@ -1476,19 +1476,19 @@ SELECT /*+ BKA() BKA() */ 1; 1 1 Warnings: -Warning 4207 Hint BKA() is ignored as conflicting/duplicated +Warning 4210 Hint BKA() is ignored as conflicting/duplicated SELECT /*+ BKA(t1) BKA(t1) */ * FROM t1; i Warnings: -Warning 4207 Hint BKA(`t1`) is ignored as conflicting/duplicated +Warning 4210 Hint BKA(`t1`) is ignored as conflicting/duplicated SELECT /*+ QB_NAME(q1) BKA(t1@q1) BKA(t1@q1) */ * FROM t1; i Warnings: -Warning 4207 Hint BKA(`t1`@`q1`) is ignored as conflicting/duplicated +Warning 4210 Hint BKA(`t1`@`q1`) is ignored as conflicting/duplicated SELECT /*+ QB_NAME(q1) NO_ICP(@q1 t1 PRIMARY) NO_ICP(@q1 t1 PRIMARY) */ * FROM t1; i Warnings: -Warning 4207 Hint NO_ICP(`t1`@`q1` `PRIMARY`) is ignored as conflicting/duplicated +Warning 4210 Hint NO_ICP(`t1`@`q1` `PRIMARY`) is ignored as conflicting/duplicated DROP TABLE t1; # # Hints inside views are not supported @@ -1497,7 +1497,7 @@ CREATE TABLE t1 (a INT, INDEX idx_a(a)); INSERT INTO t1 VALUES (1),(2); CREATE VIEW v1 AS SELECT /*+ NO_MRR(t1 idx_a) */ a FROM t1; Warnings: -Warning 4211 Optimizer hints are not supported inside view definitions +Warning 4214 Optimizer hints are not supported inside view definitions SELECT * FROM v1; a 1 @@ -1513,13 +1513,13 @@ Warnings: Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` CREATE OR REPLACE VIEW v1 AS SELECT /*+ NO_MRR(t1 idx_a) BKA(t1)*/ a FROM t1; Warnings: -Warning 4211 Optimizer hints are not supported inside view definitions +Warning 4214 Optimizer hints are not supported inside view definitions SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a` from `t1` utf8mb4 utf8mb4_uca1400_ai_ci ALTER VIEW v1 AS SELECT /*+ QB_NAME(q1)*/ a FROM t1; Warnings: -Warning 4211 Optimizer hints are not supported inside view definitions +Warning 4214 Optimizer hints are not supported inside view definitions SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a` from `t1` utf8mb4 utf8mb4_uca1400_ai_ci @@ -1686,15 +1686,15 @@ Warning 1064 Optimizer hint syntax error near 'b) */ 1 FROM t1 a, t1 b' at lin SELECT /*+ NO_ICP(i1) */ 1 FROM t1; 1 Warnings: -Warning 4209 Unresolved table name `i1`@`select#1` for NO_ICP hint +Warning 4212 Unresolved table name `i1`@`select#1` for NO_ICP hint SELECT /*+ NO_ICP(i1 i2) */ 1 FROM t1; 1 Warnings: -Warning 4210 Unresolved index name `i1`@`select#1` `i2` for NO_ICP hint +Warning 4213 Unresolved index name `i1`@`select#1` `i2` for NO_ICP hint SELECT /*+ NO_ICP(@qb ident) */ 1 FROM t1; 1 Warnings: -Warning 4208 Query block name `qb` is not found for NO_ICP hint +Warning 4211 Query block name `qb` is not found for NO_ICP hint # valid hint sequences, no warnings expected: @@ -1749,49 +1749,49 @@ CREATE INDEX 3rd_index ON t1(i, j); SELECT /*+ NO_ICP(3rd_index) */ 1 FROM t1; 1 Warnings: -Warning 4209 Unresolved table name `3rd_index`@`select#1` for NO_ICP hint +Warning 4212 Unresolved table name `3rd_index`@`select#1` for NO_ICP hint CREATE INDEX $index ON t1(j, i); SELECT /*+ NO_ICP($index) */ 1 FROM t1; 1 Warnings: -Warning 4209 Unresolved table name `$index`@`select#1` for NO_ICP hint +Warning 4212 Unresolved table name `$index`@`select#1` for NO_ICP hint CREATE TABLE ` quoted name test` (i INT); SELECT /*+ BKA(` quoted name test`) */ 1 FROM t1; 1 Warnings: -Warning 4209 Unresolved table name ` quoted name test`@`select#1` for BKA hint +Warning 4212 Unresolved table name ` quoted name test`@`select#1` for BKA hint SELECT /*+ BKA(` quoted name test`@`select#1`) */ 1 FROM t1; 1 Warnings: -Warning 4208 Query block name `select#1` is not found for BKA hint +Warning 4211 Query block name `select#1` is not found for BKA hint DROP TABLE ` quoted name test`; SET SQL_MODE = 'ANSI_QUOTES'; CREATE TABLE " quoted name test" (i INT); SELECT /*+ BKA(" quoted name test") */ 1 FROM t1; 1 Warnings: -Warning 4209 Unresolved table name " quoted name test"@"select#1" for BKA hint +Warning 4212 Unresolved table name " quoted name test"@"select#1" for BKA hint SELECT /*+ BKA(" quoted name test"@"select#1") */ 1 FROM t1; 1 Warnings: -Warning 4208 Query block name "select#1" is not found for BKA hint +Warning 4211 Query block name "select#1" is not found for BKA hint CREATE TABLE `test1``test2``` (i INT); SELECT /*+ BKA(`test1``test2```) */ 1; 1 1 Warnings: -Warning 4209 Unresolved table name "test1`test2`"@"select#1" for BKA hint +Warning 4212 Unresolved table name "test1`test2`"@"select#1" for BKA hint SELECT /*+ BKA("test1""test2""") */ 1; 1 1 Warnings: -Warning 4209 Unresolved table name "test1""test2"""@"select#1" for BKA hint +Warning 4212 Unresolved table name "test1""test2"""@"select#1" for BKA hint SET SQL_MODE = ''; # should warn: SELECT /*+ BKA(" quoted name test") */ 1 FROM t1; 1 Warnings: -Warning 4209 Unresolved table name ` quoted name test`@`select#1` for BKA hint +Warning 4212 Unresolved table name ` quoted name test`@`select#1` for BKA hint DROP TABLE ` quoted name test`; DROP TABLE `test1``test2```; # Valid hints, no warning: @@ -1843,29 +1843,29 @@ CREATE TABLE tableТ (i INT); SELECT /*+ BKA(tableТ) */ 1 FROM t1; 1 Warnings: -Warning 4209 Unresolved table name `tableТ`@`select#1` for BKA hint +Warning 4212 Unresolved table name `tableТ`@`select#1` for BKA hint SELECT /*+ BKA(test@tableТ) */ 1 FROM t1; 1 Warnings: -Warning 4208 Query block name `tableТ` is not found for BKA hint +Warning 4211 Query block name `tableТ` is not found for BKA hint DROP TABLE tableТ; CREATE TABLE таблица (i INT); SELECT /*+ BKA(`таблица`) */ 1 FROM t1; 1 Warnings: -Warning 4209 Unresolved table name `таблица`@`select#1` for BKA hint +Warning 4212 Unresolved table name `таблица`@`select#1` for BKA hint SELECT /*+ BKA(таблица) */ 1 FROM t1; 1 Warnings: -Warning 4209 Unresolved table name `таблица`@`select#1` for BKA hint +Warning 4212 Unresolved table name `таблица`@`select#1` for BKA hint SELECT /*+ BKA(test@таблица) */ 1 FROM t1; 1 Warnings: -Warning 4208 Query block name `таблица` is not found for BKA hint +Warning 4211 Query block name `таблица` is not found for BKA hint SELECT /*+ NO_ICP(`\D1`) */ 1 FROM t1; 1 Warnings: -Warning 4209 Unresolved table name `\D1`@`select#1` for NO_ICP hint +Warning 4212 Unresolved table name `\D1`@`select#1` for NO_ICP hint DROP TABLE таблица; # derived tables and other subqueries: @@ -1966,7 +1966,7 @@ NO_ICP(@qb ident) 1 1 Warnings: -Warning 4208 Query block name `qb` is not found for NO_ICP hint +Warning 4211 Query block name `qb` is not found for NO_ICP hint SELECT /*+ ? bad syntax */ 1; diff --git a/mysql-test/main/opt_hints_join_order.result b/mysql-test/main/opt_hints_join_order.result new file mode 100644 index 00000000000..bc96885e994 --- /dev/null +++ b/mysql-test/main/opt_hints_join_order.result @@ -0,0 +1,1326 @@ +set default_storage_engine=innodb; +CREATE TABLE t1 (f1 INT NOT NULL); +INSERT INTO t1 VALUES (9),(0), (7); +CREATE TABLE t2 (f1 INT NOT NULL); +INSERT INTO t2 VALUES +(5),(3),(0),(3),(1),(0),(1),(7),(1),(0),(0),(8),(4),(9),(0),(2),(0),(8),(5),(1); +CREATE TABLE t3 (f1 INT NOT NULL); +INSERT INTO t3 VALUES (9),(0), (7), (4), (5); +CREATE TABLE t4 (f1 INT NOT NULL); +INSERT INTO t4 VALUES (0), (7); +CREATE TABLE t5 (f1 INT NOT NULL, PRIMARY KEY(f1)); +INSERT INTO t5 VALUES (7); +CREATE TABLE t6(f1 INT NOT NULL, PRIMARY KEY(f1)); +INSERT INTO t6 VALUES (7); +ANALYZE TABLE t1, t2, t3, t4, t5, t6; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +test.t2 analyze status Engine-independent statistics collected +test.t2 analyze status OK +test.t3 analyze status Engine-independent statistics collected +test.t3 analyze status OK +test.t4 analyze status Engine-independent statistics collected +test.t4 analyze status OK +test.t5 analyze status Engine-independent statistics collected +test.t5 analyze status OK +test.t6 analyze status Engine-independent statistics collected +test.t6 analyze status OK +set join_cache_level = 8; +# Warning expected: hint must be ignored as malformed (no table names) +EXPLAIN EXTENDED +SELECT /*+ JOIN_PREFIX()*/ count(*) FROM t1, t2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 +1 SIMPLE t2 ALL NULL NULL NULL NULL 20 100.00 Using join buffer (flat, BNL join) +Warnings: +Warning 4215 Hint JOIN_PREFIX() is ignored as malformed +Note 1003 select count(0) AS `count(*)` from `test`.`t1` join `test`.`t2` +EXPLAIN EXTENDED +SELECT /*+ QB_NAME(q1) JOIN_PREFIX(@q1)*/ count(*) FROM t1, t2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 +1 SIMPLE t2 ALL NULL NULL NULL NULL 20 100.00 Using join buffer (flat, BNL join) +Warnings: +Warning 4215 Hint JOIN_PREFIX(@`q1` ) is ignored as malformed +Note 1003 select /*+ QB_NAME(`q1`) */ count(0) AS `count(*)` from `test`.`t1` join `test`.`t2` +# Hint must be ignored as malformed (table names are not allowed for the fixed order) +EXPLAIN EXTENDED +SELECT /*+ JOIN_FIXED_ORDER(t2)*/ count(*) FROM t1, t2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 +1 SIMPLE t2 ALL NULL NULL NULL NULL 20 100.00 Using join buffer (flat, BNL join) +Warnings: +Warning 4215 Hint JOIN_FIXED_ORDER(`t2`) is ignored as malformed +Note 1003 select count(0) AS `count(*)` from `test`.`t1` join `test`.`t2` +# Hint is applied: QB name is allowed for the fixed order +EXPLAIN EXTENDED +SELECT /*+ QB_NAME(qb1) JOIN_FIXED_ORDER(@qb1)*/ count(*) FROM t2, t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 20 100.00 +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join) +Warnings: +Note 1003 select /*+ QB_NAME(`qb1`) JOIN_FIXED_ORDER(@`qb1`) */ straight_join count(0) AS `count(*)` from `test`.`t2` join `test`.`t1` +# Invalid QB name for the fixed order +EXPLAIN EXTENDED +SELECT /*+ QB_NAME(qb1) JOIN_FIXED_ORDER(@qb3)*/ count(*) FROM t2, t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 +1 SIMPLE t2 ALL NULL NULL NULL NULL 20 100.00 Using join buffer (flat, BNL join) +Warnings: +Warning 4211 Query block name `qb3` is not found for JOIN_FIXED_ORDER hint +Note 1003 select /*+ QB_NAME(`qb1`) */ count(0) AS `count(*)` from `test`.`t2` join `test`.`t1` +EXPLAIN EXTENDED +SELECT /*+ JOIN_FIXED_ORDER()*/ STRAIGHT_JOIN count(*) FROM t1, t2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 +1 SIMPLE t2 ALL NULL NULL NULL NULL 20 100.00 Using join buffer (flat, BNL join) +Warnings: +Note 1003 select /*+ JOIN_FIXED_ORDER(@`select#1`) */ straight_join count(0) AS `count(*)` from `test`.`t1` join `test`.`t2` +# JOIN_FIXED_ORDER() cannot be combined with other join order hints +EXPLAIN EXTENDED +SELECT /*+ JOIN_PREFIX(t2) JOIN_FIXED_ORDER()*/ count(*) FROM t1, t2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 20 100.00 +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join) +Warnings: +Warning 4210 Hint JOIN_FIXED_ORDER() is ignored as conflicting/duplicated +Note 1003 select /*+ JOIN_PREFIX(@`select#1` `t2`) */ count(0) AS `count(*)` from `test`.`t1` join `test`.`t2` +EXPLAIN EXTENDED +SELECT /*+ JOIN_FIXED_ORDER() JOIN_PREFIX(t2)*/ count(*) FROM t1, t2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 +1 SIMPLE t2 ALL NULL NULL NULL NULL 20 100.00 Using join buffer (flat, BNL join) +Warnings: +Warning 4210 Hint JOIN_PREFIX(`t2`) is ignored as conflicting/duplicated +Note 1003 select /*+ JOIN_FIXED_ORDER(@`select#1`) */ straight_join count(0) AS `count(*)` from `test`.`t1` join `test`.`t2` +# Multiple join order hints of same type are not allowed (except JOIN_ORDER()) +EXPLAIN EXTENDED +SELECT /*+ JOIN_PREFIX(t1) JOIN_PREFIX(t2)*/ count(*) FROM t1, t2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 +1 SIMPLE t2 ALL NULL NULL NULL NULL 20 100.00 Using join buffer (flat, BNL join) +Warnings: +Warning 4210 Hint JOIN_PREFIX(`t2`) is ignored as conflicting/duplicated +Note 1003 select /*+ JOIN_PREFIX(@`select#1` `t1`) */ count(0) AS `count(*)` from `test`.`t1` join `test`.`t2` +EXPLAIN EXTENDED +SELECT /*+ JOIN_SUFFIX(t1) JOIN_SUFFIX(t2)*/ count(*) FROM t1, t2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 20 100.00 +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join) +Warnings: +Warning 4210 Hint JOIN_SUFFIX(`t2`) is ignored as conflicting/duplicated +Note 1003 select /*+ JOIN_SUFFIX(@`select#1` `t1`) */ count(0) AS `count(*)` from `test`.`t1` join `test`.`t2` +# Multiple JOIN_ORDER() hints are applied +EXPLAIN EXTENDED +SELECT /*+ QB_NAME(q1) JOIN_ORDER(t2,t1) JOIN_ORDER(@q1 t3,t2)*/ count(*) +FROM t1, t2, t3; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t3 ALL NULL NULL NULL NULL 5 100.00 +1 SIMPLE t2 ALL NULL NULL NULL NULL 20 100.00 Using join buffer (flat, BNL join) +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (incremental, BNL join) +Warnings: +Note 1003 select /*+ QB_NAME(`q1`) JOIN_ORDER(@`q1` `t2`,`t1`) JOIN_ORDER(@`q1` `t3`,`t2`) */ count(0) AS `count(*)` from `test`.`t1` join `test`.`t2` join `test`.`t3` +# Variation of last syntax +EXPLAIN EXTENDED +SELECT /*+ QB_NAME(q1) JOIN_ORDER(t2@q1, t1) JOIN_ORDER(t3, t2@q1)*/ count(*) +FROM t1, t2, t3; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t3 ALL NULL NULL NULL NULL 5 100.00 +1 SIMPLE t2 ALL NULL NULL NULL NULL 20 100.00 Using join buffer (flat, BNL join) +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (incremental, BNL join) +Warnings: +Note 1003 select /*+ QB_NAME(`q1`) JOIN_ORDER(@`q1` `t2`@`q1`,`t1`) JOIN_ORDER(@`q1` `t3`,`t2`@`q1`) */ count(0) AS `count(*)` from `test`.`t1` join `test`.`t2` join `test`.`t3` +# Invalid mix of notations +EXPLAIN EXTENDED +SELECT /*+ QB_NAME(q1) JOIN_PREFIX(@q1 t2, t1@q1)*/ count(*) +FROM t1, t2, t3; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 +1 SIMPLE t3 ALL NULL NULL NULL NULL 5 100.00 Using join buffer (flat, BNL join) +1 SIMPLE t2 ALL NULL NULL NULL NULL 20 100.00 Using join buffer (incremental, BNL join) +Warnings: +Warning 1064 Optimizer hint syntax error near '@q1)*/ count(*) +FROM t1, t2, t3' at line 2 +Note 1003 select count(0) AS `count(*)` from `test`.`t1` join `test`.`t2` join `test`.`t3` +# Hint is correct +EXPLAIN EXTENDED +SELECT /*+ QB_NAME(qb1) JOIN_SUFFIX(t1@qb1, t2)*/ count(*) FROM t1, t2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 +1 SIMPLE t2 ALL NULL NULL NULL NULL 20 100.00 Using join buffer (flat, BNL join) +Warnings: +Note 1003 select /*+ QB_NAME(`qb1`) JOIN_SUFFIX(@`qb1` `t1`@`qb1`,`t2`) */ count(0) AS `count(*)` from `test`.`t1` join `test`.`t2` +EXPLAIN EXTENDED +SELECT /*+ QB_NAME(qb1) JOIN_PREFIX(@qb1, t2)*/ count(*) FROM t1, t2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 +1 SIMPLE t2 ALL NULL NULL NULL NULL 20 100.00 Using join buffer (flat, BNL join) +Warnings: +Warning 1064 Optimizer hint syntax error near ', t2)*/ count(*) FROM t1, t2' at line 2 +Note 1003 select count(0) AS `count(*)` from `test`.`t1` join `test`.`t2` +# Invalid table name +EXPLAIN EXTENDED +SELECT /*+ JOIN_SUFFIX(t3)*/ count(*) FROM t1, t2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 +1 SIMPLE t2 ALL NULL NULL NULL NULL 20 100.00 Using join buffer (flat, BNL join) +Warnings: +Warning 4212 Unresolved table name `t3` for JOIN_SUFFIX hint +Note 1003 select count(0) AS `count(*)` from `test`.`t1` join `test`.`t2` +# Invalid query block name +EXPLAIN EXTENDED +SELECT /*+ QB_NAME(qb1) JOIN_SUFFIX(@qbXXX t1)*/ count(*) FROM t1, t2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 +1 SIMPLE t2 ALL NULL NULL NULL NULL 20 100.00 Using join buffer (flat, BNL join) +Warnings: +Warning 4211 Query block name `qbXXX` is not found for JOIN_SUFFIX hint +Note 1003 select /*+ QB_NAME(`qb1`) */ count(0) AS `count(*)` from `test`.`t1` join `test`.`t2` +EXPLAIN EXTENDED +SELECT /*+ QB_NAME(qb1) JOIN_SUFFIX(t1, t2@qb3)*/ count(*) FROM t1, t2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 +1 SIMPLE t2 ALL NULL NULL NULL NULL 20 100.00 Using join buffer (flat, BNL join) +Warnings: +Warning 4212 Unresolved table name `t2`@`qb3` for JOIN_SUFFIX hint +Note 1003 select /*+ QB_NAME(`qb1`) */ count(0) AS `count(*)` from `test`.`t1` join `test`.`t2` +EXPLAIN EXTENDED +SELECT /*+ QB_NAME(qb1) JOIN_FIXED_ORDER(@qbXXX)*/ count(*) FROM t2, t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 +1 SIMPLE t2 ALL NULL NULL NULL NULL 20 100.00 Using join buffer (flat, BNL join) +Warnings: +Warning 4211 Query block name `qbXXX` is not found for JOIN_FIXED_ORDER hint +Note 1003 select /*+ QB_NAME(`qb1`) */ count(0) AS `count(*)` from `test`.`t2` join `test`.`t1` +# Warning expected as the hint must not confuse `t2` in the subquery +# with `t2` in the join +EXPLAIN EXTENDED +SELECT /*+ JOIN_PREFIX(t2@subq)*/ (SELECT /*+ QB_NAME(subq)*/ max(f1) FROM t2) as SQ, f1 +FROM t2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 20 100.00 +2 SUBQUERY t2 ALL NULL NULL NULL NULL 20 100.00 +Warnings: +Warning 4212 Unresolved table name `t2`@`subq` for JOIN_PREFIX hint +Note 1003 /* select#1 */ select (/* select#2 */ select /*+ QB_NAME(`subq`) */ max(`test`.`t2`.`f1`) from `test`.`t2`) AS `SQ`,`test`.`t2`.`f1` AS `f1` from `test`.`t2` +# No more than 64 join order hints are allowed. It is hard to construct +# a test case where 64 hints will be applicable and only one, exceeding +# the maximum, will produce a warning. Usually so many hints will conflict +# with each other and generate warnings. +# But in the case below we can observe that the first warning +# is about JOIN_ORDER(t1,t2,t3,t4,t5,t6) which is actually +# the last hint in the list, and it is the 65th in order. +# This happens because the check for exceeding the maximum is performed +# during the preparation phase, while other checks are performed during +# hints application. So, if JOIN_ORDER(t1,t2,t3,t4,t5,t6) +# is mentioned first in the list of warnings, the test case passes. +EXPLAIN EXTENDED +SELECT /*+ +JOIN_PREFIX(t2,t1) JOIN_SUFFIX(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) +JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) +JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) +JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) +JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) +JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) +JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) +JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) +JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) +JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) +JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) +JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) +JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) +JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) +JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) +JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) +JOIN_ORDER(t1,t2,t3,t4,t5,t6) */ +count(*) FROM t1, t2, t3; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 20 100.00 +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join) +1 SIMPLE t3 ALL NULL NULL NULL NULL 5 100.00 Using join buffer (incremental, BNL join) +Warnings: +Warning 4210 Hint JOIN_ORDER(`t1`,`t2`,`t3`,`t4`,`t5`,`t6`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_SUFFIX(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_ORDER(`t3`,`t2`) is ignored as conflicting/duplicated +Note 1003 select /*+ JOIN_PREFIX(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t1`) */ count(0) AS `count(*)` from `test`.`t1` join `test`.`t2` join `test`.`t3` +# Original query with no hints +SELECT count(*) FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT f1 FROM t4) AND t2.f1 IN (SELECT f1 FROM t5); +count(*) +10 +explain extended SELECT count(*) FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT f1 FROM t4) AND t2.f1 IN (SELECT f1 FROM t5); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t5 ALL PRIMARY NULL NULL NULL 1 100.00 +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join) +1 PRIMARY t4 hash_ALL NULL #hash#$hj 4 test.t1.f1 2 50.00 Using where; FirstMatch(t1); Using join buffer (incremental, BNLH join) +1 PRIMARY t2 hash_ALL NULL #hash#$hj 4 test.t5.f1 20 11.11 Using where; Using join buffer (incremental, BNLH join) +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 100.00 Using join buffer (incremental, BNL join) +Warnings: +Note 1003 select count(0) AS `count(*)` from `test`.`t5` semi join (`test`.`t4`) join `test`.`t1` join `test`.`t2` join `test`.`t3` where `test`.`t4`.`f1` = `test`.`t1`.`f1` and `test`.`t2`.`f1` = `test`.`t5`.`f1` +# Check name resolving +SELECT /*+ QB_NAME(q1) JOIN_PREFIX(t3, t2, t2@subq2) */ count(*) FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t2) AND +t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t2); +count(*) +300 +explain extended SELECT /*+ QB_NAME(q1) JOIN_PREFIX(t3, t2, t2@subq2) */ count(*) FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t2) AND +t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t2); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 100.00 +1 PRIMARY t2 ALL NULL NULL NULL NULL 20 100.00 Using join buffer (flat, BNL join) +1 PRIMARY t2 hash_ALL NULL #hash#$hj 4 test.t2.f1 20 5.00 Using where; FirstMatch(t2); Using join buffer (incremental, BNLH join) +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (incremental, BNL join) +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 100.00 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 20 100.00 +Warnings: +Note 1003 select /*+ QB_NAME(`q1`) JOIN_PREFIX(@`q1` `t3`,`t2`,`t2`@`subq2`) */ count(0) AS `count(*)` from `test`.`t1` semi join (`test`.`t2`) semi join (`test`.`t2`) join `test`.`t2` join `test`.`t3` where `test`.`t2`.`f1` = `test`.`t2`.`f1` +# Check conflicting hints +# Second JOIN_PREFIX is conflicting +SELECT /*+ JOIN_PREFIX(t3, t2, t1) JOIN_PREFIX(t2, t1) */ count(*) FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +count(*) +10 +Warnings: +Warning 4210 Hint JOIN_PREFIX(`t2`,`t1`) is ignored as conflicting/duplicated +explain extended SELECT /*+ JOIN_PREFIX(t3, t2, t1) JOIN_PREFIX(t2, t1) */ count(*) FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 100.00 +1 PRIMARY t2 ALL NULL NULL NULL NULL 20 100.00 Using join buffer (flat, BNL join) +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (incremental, BNL join) +1 PRIMARY t5 ALL PRIMARY NULL NULL NULL 1 100.00 Using where; Using join buffer (incremental, BNL join) +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 100.00 +2 MATERIALIZED t4 ALL NULL NULL NULL NULL 2 100.00 +Warnings: +Warning 4210 Hint JOIN_PREFIX(`t2`,`t1`) is ignored as conflicting/duplicated +Note 1003 select /*+ JOIN_PREFIX(@`select#1` `t3`,`t2`,`t1`) */ count(0) AS `count(*)` from `test`.`t5` semi join (`test`.`t4`) join `test`.`t1` join `test`.`t2` join `test`.`t3` where `test`.`t5`.`f1` = `test`.`t2`.`f1` +# Second JOIN_SUFFIX is conflicting +SELECT /*+ JOIN_SUFFIX(t3, t2) JOIN_SUFFIX(t2, t1) */ count(*) FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +count(*) +10 +Warnings: +Warning 4210 Hint JOIN_SUFFIX(`t2`,`t1`) is ignored as conflicting/duplicated +explain extended SELECT /*+ JOIN_SUFFIX(t3, t2) JOIN_SUFFIX(t2, t1) */ count(*) FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t5 ALL PRIMARY NULL NULL NULL 1 100.00 +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join) +1 PRIMARY t4 hash_ALL NULL #hash#$hj 4 test.t1.f1 2 50.00 Using where; FirstMatch(t1); Using join buffer (incremental, BNLH join) +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 100.00 Using join buffer (incremental, BNL join) +1 PRIMARY t2 hash_ALL NULL #hash#$hj 4 test.t5.f1 20 11.11 Using where; Using join buffer (incremental, BNLH join) +Warnings: +Warning 4210 Hint JOIN_SUFFIX(`t2`,`t1`) is ignored as conflicting/duplicated +Note 1003 select /*+ JOIN_SUFFIX(@`select#1` `t3`,`t2`) */ count(0) AS `count(*)` from `test`.`t5` semi join (`test`.`t4`) join `test`.`t1` join `test`.`t2` join `test`.`t3` where `test`.`t4`.`f1` = `test`.`t1`.`f1` and `test`.`t2`.`f1` = `test`.`t5`.`f1` +# Both JOIN_ORDERs applicable +SELECT /*+ JOIN_ORDER(t3, t2) JOIN_ORDER(t1, t2, t5@subq2) */ count(*) +FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +count(*) +10 +explain extended SELECT /*+ JOIN_ORDER(t3, t2) JOIN_ORDER(t1, t2, t5@subq2) */ count(*) +FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t4 ALL NULL NULL NULL NULL 2 100.00 Start temporary +1 PRIMARY t1 hash_ALL NULL #hash#$hj 4 test.t4.f1 3 16.67 Using where; End temporary; Using join buffer (flat, BNLH join) +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 100.00 Using join buffer (incremental, BNL join) +1 PRIMARY t2 ALL NULL NULL NULL NULL 20 100.00 Using join buffer (incremental, BNL join) +1 PRIMARY t5 ALL PRIMARY NULL NULL NULL 1 100.00 Using where; Using join buffer (incremental, BNL join) +Warnings: +Note 1003 select /*+ JOIN_ORDER(@`select#1` `t3`,`t2`) JOIN_ORDER(@`select#1` `t1`,`t2`,`t5`@`subq2`) */ count(0) AS `count(*)` from `test`.`t5` semi join (`test`.`t4`) join `test`.`t1` join `test`.`t2` join `test`.`t3` where `test`.`t1`.`f1` = `test`.`t4`.`f1` and `test`.`t5`.`f1` = `test`.`t2`.`f1` +# Unresolved table name t7 in JOIN_ORDER hint, hint ignored +SELECT /*+ JOIN_ORDER(t1, t7, t5) */ count(*) FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +count(*) +10 +Warnings: +Warning 4212 Unresolved table name `t7` for JOIN_ORDER hint +explain extended SELECT /*+ JOIN_ORDER(t1, t7, t5) */ count(*) FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t5 ALL PRIMARY NULL NULL NULL 1 100.00 +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join) +1 PRIMARY t4 hash_ALL NULL #hash#$hj 4 test.t1.f1 2 50.00 Using where; FirstMatch(t1); Using join buffer (incremental, BNLH join) +1 PRIMARY t2 hash_ALL NULL #hash#$hj 4 test.t5.f1 20 11.11 Using where; Using join buffer (incremental, BNLH join) +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 100.00 Using join buffer (incremental, BNL join) +Warnings: +Warning 4212 Unresolved table name `t7` for JOIN_ORDER hint +Note 1003 select count(0) AS `count(*)` from `test`.`t5` semi join (`test`.`t4`) join `test`.`t1` join `test`.`t2` join `test`.`t3` where `test`.`t4`.`f1` = `test`.`t1`.`f1` and `test`.`t2`.`f1` = `test`.`t5`.`f1` +# All hints are applicable +SELECT /*+ JOIN_PREFIX(t2, t5@subq2, t4@subq1) +JOIN_ORDER(t4@subq1, t3) JOIN_SUFFIX(t1) */ count(*) +FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +count(*) +10 +explain extended SELECT /*+ JOIN_PREFIX(t2, t5@subq2, t4@subq1) +JOIN_ORDER(t4@subq1, t3) JOIN_SUFFIX(t1) */ count(*) +FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 20 100.00 +1 PRIMARY t5 ALL PRIMARY NULL NULL NULL 1 100.00 Using where; Using join buffer (flat, BNL join) +1 PRIMARY t4 ALL NULL NULL NULL NULL 2 100.00 Start temporary; Using join buffer (incremental, BNL join) +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 100.00 Using join buffer (incremental, BNL join) +1 PRIMARY t1 hash_ALL NULL #hash#$hj 4 test.t4.f1 3 16.67 Using where; End temporary; Using join buffer (incremental, BNLH join) +Warnings: +Note 1003 select /*+ JOIN_PREFIX(@`select#1` `t2`,`t5`@`subq2`,`t4`@`subq1`) JOIN_ORDER(@`select#1` `t4`@`subq1`,`t3`) JOIN_SUFFIX(@`select#1` `t1`) */ count(0) AS `count(*)` from `test`.`t5` semi join (`test`.`t4`) join `test`.`t1` join `test`.`t2` join `test`.`t3` where `test`.`t1`.`f1` = `test`.`t4`.`f1` and `test`.`t5`.`f1` = `test`.`t2`.`f1` +# Second JOIN_ORDER is ignored +SELECT /*+ JOIN_ORDER(t3, t2) JOIN_ORDER(t2, t3) */ count(*) FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +count(*) +10 +Warnings: +Warning 4210 Hint JOIN_ORDER(`t2`,`t3`) is ignored as conflicting/duplicated +explain extended SELECT /*+ JOIN_ORDER(t3, t2) JOIN_ORDER(t2, t3) */ count(*) FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t5 ALL PRIMARY NULL NULL NULL 1 100.00 +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join) +1 PRIMARY t4 hash_ALL NULL #hash#$hj 4 test.t1.f1 2 50.00 Using where; FirstMatch(t1); Using join buffer (incremental, BNLH join) +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 100.00 Using join buffer (incremental, BNL join) +1 PRIMARY t2 hash_ALL NULL #hash#$hj 4 test.t5.f1 20 11.11 Using where; Using join buffer (incremental, BNLH join) +Warnings: +Warning 4210 Hint JOIN_ORDER(`t2`,`t3`) is ignored as conflicting/duplicated +Note 1003 select /*+ JOIN_ORDER(@`select#1` `t3`,`t2`) */ count(0) AS `count(*)` from `test`.`t5` semi join (`test`.`t4`) join `test`.`t1` join `test`.`t2` join `test`.`t3` where `test`.`t4`.`f1` = `test`.`t1`.`f1` and `test`.`t2`.`f1` = `test`.`t5`.`f1` +# JOIN_SUFFIX is ignored +SELECT /*+ JOIN_ORDER(t3, t2) JOIN_SUFFIX(t3) */ count(*) FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +count(*) +10 +Warnings: +Warning 4210 Hint JOIN_SUFFIX(`t3`) is ignored as conflicting/duplicated +explain extended SELECT /*+ JOIN_ORDER(t3, t2) JOIN_SUFFIX(t3) */ count(*) FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t5 ALL PRIMARY NULL NULL NULL 1 100.00 +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join) +1 PRIMARY t4 hash_ALL NULL #hash#$hj 4 test.t1.f1 2 50.00 Using where; FirstMatch(t1); Using join buffer (incremental, BNLH join) +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 100.00 Using join buffer (incremental, BNL join) +1 PRIMARY t2 hash_ALL NULL #hash#$hj 4 test.t5.f1 20 11.11 Using where; Using join buffer (incremental, BNLH join) +Warnings: +Warning 4210 Hint JOIN_SUFFIX(`t3`) is ignored as conflicting/duplicated +Note 1003 select /*+ JOIN_ORDER(@`select#1` `t3`,`t2`) */ count(0) AS `count(*)` from `test`.`t5` semi join (`test`.`t4`) join `test`.`t1` join `test`.`t2` join `test`.`t3` where `test`.`t4`.`f1` = `test`.`t1`.`f1` and `test`.`t2`.`f1` = `test`.`t5`.`f1` +# JOIN_PREFIX is ignored +SELECT /*+ JOIN_ORDER(t3, t2) JOIN_PREFIX(t2) */ count(*) FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +count(*) +10 +Warnings: +Warning 4210 Hint JOIN_PREFIX(`t2`) is ignored as conflicting/duplicated +explain extended SELECT /*+ JOIN_ORDER(t3, t2) JOIN_PREFIX(t2) */ count(*) FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t5 ALL PRIMARY NULL NULL NULL 1 100.00 +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join) +1 PRIMARY t4 hash_ALL NULL #hash#$hj 4 test.t1.f1 2 50.00 Using where; FirstMatch(t1); Using join buffer (incremental, BNLH join) +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 100.00 Using join buffer (incremental, BNL join) +1 PRIMARY t2 hash_ALL NULL #hash#$hj 4 test.t5.f1 20 11.11 Using where; Using join buffer (incremental, BNLH join) +Warnings: +Warning 4210 Hint JOIN_PREFIX(`t2`) is ignored as conflicting/duplicated +Note 1003 select /*+ JOIN_ORDER(@`select#1` `t3`,`t2`) */ count(0) AS `count(*)` from `test`.`t5` semi join (`test`.`t4`) join `test`.`t1` join `test`.`t2` join `test`.`t3` where `test`.`t4`.`f1` = `test`.`t1`.`f1` and `test`.`t2`.`f1` = `test`.`t5`.`f1` +# All hints are applicable +SELECT /*+ JOIN_ORDER(t4@subq1, t3) JOIN_SUFFIX(t1) JOIN_PREFIX(t2, t5@subq2, t4@subq1) */ count(*) +FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +count(*) +10 +explain extended SELECT /*+ JOIN_ORDER(t4@subq1, t3) JOIN_SUFFIX(t1) JOIN_PREFIX(t2, t5@subq2, t4@subq1) */ count(*) +FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 20 100.00 +1 PRIMARY t5 ALL PRIMARY NULL NULL NULL 1 100.00 Using where; Using join buffer (flat, BNL join) +1 PRIMARY t4 ALL NULL NULL NULL NULL 2 100.00 Start temporary; Using join buffer (incremental, BNL join) +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 100.00 Using join buffer (incremental, BNL join) +1 PRIMARY t1 hash_ALL NULL #hash#$hj 4 test.t4.f1 3 16.67 Using where; End temporary; Using join buffer (incremental, BNLH join) +Warnings: +Note 1003 select /*+ JOIN_ORDER(@`select#1` `t4`@`subq1`,`t3`) JOIN_SUFFIX(@`select#1` `t1`) JOIN_PREFIX(@`select#1` `t2`,`t5`@`subq2`,`t4`@`subq1`) */ count(0) AS `count(*)` from `test`.`t5` semi join (`test`.`t4`) join `test`.`t1` join `test`.`t2` join `test`.`t3` where `test`.`t1`.`f1` = `test`.`t4`.`f1` and `test`.`t5`.`f1` = `test`.`t2`.`f1` +# JOIN_PREFIX with all tables. +SELECT /*+ JOIN_PREFIX(t2, t5@subq2, t4@subq1, t3, t1) */ count(*) +FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +count(*) +10 +explain extended SELECT /*+ JOIN_PREFIX(t2, t5@subq2, t4@subq1, t3, t1) */ count(*) +FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 20 100.00 +1 PRIMARY t5 ALL PRIMARY NULL NULL NULL 1 100.00 Using where; Using join buffer (flat, BNL join) +1 PRIMARY t4 ALL NULL NULL NULL NULL 2 100.00 Start temporary; Using join buffer (incremental, BNL join) +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 100.00 Using join buffer (incremental, BNL join) +1 PRIMARY t1 hash_ALL NULL #hash#$hj 4 test.t4.f1 3 16.67 Using where; End temporary; Using join buffer (incremental, BNLH join) +Warnings: +Note 1003 select /*+ JOIN_PREFIX(@`select#1` `t2`,`t5`@`subq2`,`t4`@`subq1`,`t3`,`t1`) */ count(0) AS `count(*)` from `test`.`t5` semi join (`test`.`t4`) join `test`.`t1` join `test`.`t2` join `test`.`t3` where `test`.`t1`.`f1` = `test`.`t4`.`f1` and `test`.`t5`.`f1` = `test`.`t2`.`f1` +# JOIN_SUFFIX with all tables. +SELECT /*+ JOIN_SUFFIX(t2, t5@subq2, t4@subq1, t3, t1) */ count(*) +FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +count(*) +10 +explain extended SELECT /*+ JOIN_SUFFIX(t2, t5@subq2, t4@subq1, t3, t1) */ count(*) +FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 20 100.00 +1 PRIMARY t5 ALL PRIMARY NULL NULL NULL 1 100.00 Using where; Using join buffer (flat, BNL join) +1 PRIMARY t4 ALL NULL NULL NULL NULL 2 100.00 Start temporary; Using join buffer (incremental, BNL join) +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 100.00 Using join buffer (incremental, BNL join) +1 PRIMARY t1 hash_ALL NULL #hash#$hj 4 test.t4.f1 3 16.67 Using where; End temporary; Using join buffer (incremental, BNLH join) +Warnings: +Note 1003 select /*+ JOIN_SUFFIX(@`select#1` `t2`,`t5`@`subq2`,`t4`@`subq1`,`t3`,`t1`) */ count(0) AS `count(*)` from `test`.`t5` semi join (`test`.`t4`) join `test`.`t1` join `test`.`t2` join `test`.`t3` where `test`.`t1`.`f1` = `test`.`t4`.`f1` and `test`.`t5`.`f1` = `test`.`t2`.`f1` +# JOIN_ORDER with all tables. +SELECT /*+ JOIN_ORDER(t2, t5@subq2, t4@subq1, t3, t1) */ count(*) +FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +count(*) +10 +explain extended SELECT /*+ JOIN_ORDER(t2, t5@subq2, t4@subq1, t3, t1) */ count(*) +FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 20 100.00 +1 PRIMARY t5 ALL PRIMARY NULL NULL NULL 1 100.00 Using where; Using join buffer (flat, BNL join) +1 PRIMARY t4 ALL NULL NULL NULL NULL 2 100.00 Start temporary; Using join buffer (incremental, BNL join) +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 100.00 Using join buffer (incremental, BNL join) +1 PRIMARY t1 hash_ALL NULL #hash#$hj 4 test.t4.f1 3 16.67 Using where; End temporary; Using join buffer (incremental, BNLH join) +Warnings: +Note 1003 select /*+ JOIN_ORDER(@`select#1` `t2`,`t5`@`subq2`,`t4`@`subq1`,`t3`,`t1`) */ count(0) AS `count(*)` from `test`.`t5` semi join (`test`.`t4`) join `test`.`t1` join `test`.`t2` join `test`.`t3` where `test`.`t1`.`f1` = `test`.`t4`.`f1` and `test`.`t5`.`f1` = `test`.`t2`.`f1` +# JOIN_PREFIX, JOIN_ORDER, JOIN_SUFFIX with all tables. +SELECT /*+ JOIN_SUFFIX(t2, t5@subq2, t4@subq1, t3, t1) +JOIN_ORDER(t2, t5@subq2, t4@subq1, t3, t1) +JOIN_PREFIX(t2, t5@subq2, t4@subq1, t3, t1) */ count(*) +FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +count(*) +10 +explain extended SELECT /*+ JOIN_SUFFIX(t2, t5@subq2, t4@subq1, t3, t1) +JOIN_ORDER(t2, t5@subq2, t4@subq1, t3, t1) +JOIN_PREFIX(t2, t5@subq2, t4@subq1, t3, t1) */ count(*) +FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 20 100.00 +1 PRIMARY t5 ALL PRIMARY NULL NULL NULL 1 100.00 Using where; Using join buffer (flat, BNL join) +1 PRIMARY t4 ALL NULL NULL NULL NULL 2 100.00 Start temporary; Using join buffer (incremental, BNL join) +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 100.00 Using join buffer (incremental, BNL join) +1 PRIMARY t1 hash_ALL NULL #hash#$hj 4 test.t4.f1 3 16.67 Using where; End temporary; Using join buffer (incremental, BNLH join) +Warnings: +Note 1003 select /*+ JOIN_SUFFIX(@`select#1` `t2`,`t5`@`subq2`,`t4`@`subq1`,`t3`,`t1`) JOIN_ORDER(@`select#1` `t2`,`t5`@`subq2`,`t4`@`subq1`,`t3`,`t1`) JOIN_PREFIX(@`select#1` `t2`,`t5`@`subq2`,`t4`@`subq1`,`t3`,`t1`) */ count(0) AS `count(*)` from `test`.`t5` semi join (`test`.`t4`) join `test`.`t1` join `test`.`t2` join `test`.`t3` where `test`.`t1`.`f1` = `test`.`t4`.`f1` and `test`.`t5`.`f1` = `test`.`t2`.`f1` +# JOIN_ORDER is ignored due to STRAIGHT_JOIN. +SELECT /*+ QB_NAME(q1) JOIN_ORDER(t2, t1) */ STRAIGHT_JOIN count(*) +FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +count(*) +10 +Warnings: +Warning 4210 Hint JOIN_ORDER(`t2`,`t1`) is ignored as conflicting/duplicated +explain extended SELECT /*+ QB_NAME(q1) JOIN_ORDER(t2, t1) */ STRAIGHT_JOIN count(*) +FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where +1 PRIMARY t2 ALL NULL NULL NULL NULL 20 100.00 Using where; Using join buffer (flat, BNL join) +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 100.00 Using join buffer (incremental, BNL join) +3 MATERIALIZED t5 ALL PRIMARY NULL NULL NULL 1 100.00 +2 DEPENDENT SUBQUERY t4 ALL NULL NULL NULL NULL 2 100.00 Using where +Warnings: +Warning 4210 Hint JOIN_ORDER(`t2`,`t1`) is ignored as conflicting/duplicated +Note 1003 /* select#1 */ select /*+ QB_NAME(`q1`) */ straight_join count(0) AS `count(*)` from `test`.`t1` join `test`.`t2` join `test`.`t3` where <`test`.`t1`.`f1`>((`test`.`t1`.`f1`,(/* select#2 */ select /*+ QB_NAME(`subq1`) */ `test`.`t4`.`f1` from `test`.`t4` where (`test`.`t1`.`f1`) = `test`.`t4`.`f1`))) and <`test`.`t2`.`f1`>((`test`.`t2`.`f1`,`test`.`t2`.`f1` in ( (/* select#3 */ select /*+ QB_NAME(`subq2`) */ `test`.`t5`.`f1` from `test`.`t5` ), (`test`.`t2`.`f1` in on distinct_key where `test`.`t2`.`f1` = ``.`f1`)))) +# Test JOIN_FIXED_ORDER. +SELECT /*+ QB_NAME(q1) JOIN_FIXED_ORDER(@q1) */ count(*) FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +count(*) +10 +explain extended SELECT /*+ QB_NAME(q1) JOIN_FIXED_ORDER(@q1) */ count(*) FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where +1 PRIMARY t2 ALL NULL NULL NULL NULL 20 100.00 Using where; Using join buffer (flat, BNL join) +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 100.00 Using join buffer (incremental, BNL join) +3 MATERIALIZED t5 ALL PRIMARY NULL NULL NULL 1 100.00 +2 DEPENDENT SUBQUERY t4 ALL NULL NULL NULL NULL 2 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select /*+ QB_NAME(`q1`) JOIN_FIXED_ORDER(@`q1`) */ straight_join count(0) AS `count(*)` from `test`.`t1` join `test`.`t2` join `test`.`t3` where <`test`.`t1`.`f1`>((`test`.`t1`.`f1`,(/* select#2 */ select /*+ QB_NAME(`subq1`) */ `test`.`t4`.`f1` from `test`.`t4` where (`test`.`t1`.`f1`) = `test`.`t4`.`f1`))) and <`test`.`t2`.`f1`>((`test`.`t2`.`f1`,`test`.`t2`.`f1` in ( (/* select#3 */ select /*+ QB_NAME(`subq2`) */ `test`.`t5`.`f1` from `test`.`t5` ), (`test`.`t2`.`f1` in on distinct_key where `test`.`t2`.`f1` = ``.`f1`)))) +SELECT /*+ JOIN_FIXED_ORDER() */ count(*) FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +count(*) +10 +explain extended SELECT /*+ JOIN_FIXED_ORDER() */ count(*) FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where +1 PRIMARY t2 ALL NULL NULL NULL NULL 20 100.00 Using where; Using join buffer (flat, BNL join) +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 100.00 Using join buffer (incremental, BNL join) +3 MATERIALIZED t5 ALL PRIMARY NULL NULL NULL 1 100.00 +2 DEPENDENT SUBQUERY t4 ALL NULL NULL NULL NULL 2 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select /*+ JOIN_FIXED_ORDER(@`select#1`) */ straight_join count(0) AS `count(*)` from `test`.`t1` join `test`.`t2` join `test`.`t3` where <`test`.`t1`.`f1`>((`test`.`t1`.`f1`,(/* select#2 */ select /*+ QB_NAME(`subq1`) */ `test`.`t4`.`f1` from `test`.`t4` where (`test`.`t1`.`f1`) = `test`.`t4`.`f1`))) and <`test`.`t2`.`f1`>((`test`.`t2`.`f1`,`test`.`t2`.`f1` in ( (/* select#3 */ select /*+ QB_NAME(`subq2`) */ `test`.`t5`.`f1` from `test`.`t5` ), (`test`.`t2`.`f1` in on distinct_key where `test`.`t2`.`f1` = ``.`f1`)))) +SELECT /*+ QB_NAME(q1) */ count(*) FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +count(*) +10 +explain extended SELECT /*+ QB_NAME(q1) */ count(*) FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t5 ALL PRIMARY NULL NULL NULL 1 100.00 +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join) +1 PRIMARY t4 hash_ALL NULL #hash#$hj 4 test.t1.f1 2 50.00 Using where; FirstMatch(t1); Using join buffer (incremental, BNLH join) +1 PRIMARY t2 hash_ALL NULL #hash#$hj 4 test.t5.f1 20 11.11 Using where; Using join buffer (incremental, BNLH join) +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 100.00 Using join buffer (incremental, BNL join) +Warnings: +Note 1003 select /*+ QB_NAME(`q1`) */ count(0) AS `count(*)` from `test`.`t5` semi join (`test`.`t4`) join `test`.`t1` join `test`.`t2` join `test`.`t3` where `test`.`t4`.`f1` = `test`.`t1`.`f1` and `test`.`t2`.`f1` = `test`.`t5`.`f1` +# Testing STRAIGHT_JOIN +SELECT count(*) FROM t1 JOIN t2 STRAIGHT_JOIN t3 +WHERE t1.f1 IN (SELECT f1 FROM t4) AND t2.f1 IN (SELECT f1 FROM t5); +count(*) +10 +explain extended SELECT count(*) FROM t1 JOIN t2 STRAIGHT_JOIN t3 +WHERE t1.f1 IN (SELECT f1 FROM t4) AND t2.f1 IN (SELECT f1 FROM t5); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t5 ALL PRIMARY NULL NULL NULL 1 100.00 +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join) +1 PRIMARY t4 hash_ALL NULL #hash#$hj 4 test.t1.f1 2 50.00 Using where; FirstMatch(t1); Using join buffer (incremental, BNLH join) +1 PRIMARY t2 hash_ALL NULL #hash#$hj 4 test.t5.f1 20 11.11 Using where; Using join buffer (incremental, BNLH join) +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 100.00 Using join buffer (incremental, BNL join) +Warnings: +Note 1003 select count(0) AS `count(*)` from `test`.`t5` semi join (`test`.`t4`) join `test`.`t1` join `test`.`t2` straight_join `test`.`t3` where `test`.`t4`.`f1` = `test`.`t1`.`f1` and `test`.`t2`.`f1` = `test`.`t5`.`f1` +# t3 can not be first +SELECT /*+ JOIN_PREFIX(t3, t1) */ count(*) FROM t1 JOIN t2 STRAIGHT_JOIN t3 +WHERE t1.f1 IN (SELECT f1 FROM t4) AND t2.f1 IN (SELECT f1 FROM t5); +count(*) +10 +Warnings: +Warning 4210 Hint JOIN_PREFIX(`t3`,`t1`) is ignored as conflicting/duplicated +explain extended SELECT /*+ JOIN_PREFIX(t3, t1) */ count(*) FROM t1 JOIN t2 STRAIGHT_JOIN t3 +WHERE t1.f1 IN (SELECT f1 FROM t4) AND t2.f1 IN (SELECT f1 FROM t5); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t5 ALL PRIMARY NULL NULL NULL 1 100.00 +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join) +1 PRIMARY t4 hash_ALL NULL #hash#$hj 4 test.t1.f1 2 50.00 Using where; FirstMatch(t1); Using join buffer (incremental, BNLH join) +1 PRIMARY t2 hash_ALL NULL #hash#$hj 4 test.t5.f1 20 11.11 Using where; Using join buffer (incremental, BNLH join) +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 100.00 Using join buffer (incremental, BNL join) +Warnings: +Warning 4210 Hint JOIN_PREFIX(`t3`,`t1`) is ignored as conflicting/duplicated +Note 1003 select count(0) AS `count(*)` from `test`.`t5` semi join (`test`.`t4`) join `test`.`t1` join `test`.`t2` straight_join `test`.`t3` where `test`.`t4`.`f1` = `test`.`t1`.`f1` and `test`.`t2`.`f1` = `test`.`t5`.`f1` +# Hint is applicable +SELECT /*+ JOIN_PREFIX(t1, t2, t3) */ count(*) FROM t1 JOIN t2 STRAIGHT_JOIN t3 +WHERE t1.f1 IN (SELECT f1 FROM t4) AND t2.f1 IN (SELECT f1 FROM t5); +count(*) +10 +explain extended SELECT /*+ JOIN_PREFIX(t1, t2, t3) */ count(*) FROM t1 JOIN t2 STRAIGHT_JOIN t3 +WHERE t1.f1 IN (SELECT f1 FROM t4) AND t2.f1 IN (SELECT f1 FROM t5); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 +1 PRIMARY t2 ALL NULL NULL NULL NULL 20 100.00 Using join buffer (flat, BNL join) +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 100.00 Using join buffer (incremental, BNL join) +1 PRIMARY t5 ALL PRIMARY NULL NULL NULL 1 100.00 Using where; Using join buffer (incremental, BNL join) +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 100.00 +2 MATERIALIZED t4 ALL NULL NULL NULL NULL 2 100.00 +Warnings: +Note 1003 select /*+ JOIN_PREFIX(@`select#1` `t1`,`t2`,`t3`) */ count(0) AS `count(*)` from `test`.`t5` semi join (`test`.`t4`) join `test`.`t1` join `test`.`t2` straight_join `test`.`t3` where `test`.`t5`.`f1` = `test`.`t2`.`f1` +# Hint is applicable +SELECT /*+ JOIN_SUFFIX(t4, t5) */ count(*) FROM t1 JOIN t2 STRAIGHT_JOIN t3 +WHERE t1.f1 IN (SELECT f1 FROM t4) AND t2.f1 IN (SELECT f1 FROM t5); +count(*) +10 +explain extended SELECT /*+ JOIN_SUFFIX(t4, t5) */ count(*) FROM t1 JOIN t2 STRAIGHT_JOIN t3 +WHERE t1.f1 IN (SELECT f1 FROM t4) AND t2.f1 IN (SELECT f1 FROM t5); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 +1 PRIMARY t2 ALL NULL NULL NULL NULL 20 100.00 Using join buffer (flat, BNL join) +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 100.00 Using join buffer (incremental, BNL join) +1 PRIMARY t4 hash_ALL NULL #hash#$hj 4 test.t1.f1 2 50.00 Using where; FirstMatch(t3); Using join buffer (incremental, BNLH join) +1 PRIMARY t5 ALL PRIMARY NULL NULL NULL 1 100.00 Using where; Using join buffer (incremental, BNL join) +Warnings: +Note 1003 select /*+ JOIN_SUFFIX(@`select#1` `t4`,`t5`) */ count(0) AS `count(*)` from `test`.`t5` semi join (`test`.`t4`) join `test`.`t1` join `test`.`t2` straight_join `test`.`t3` where `test`.`t4`.`f1` = `test`.`t1`.`f1` and `test`.`t5`.`f1` = `test`.`t2`.`f1` +# Alternative syntax +SELECT /*+ QB_NAME(q1) JOIN_ORDER(@q1 t2, t3, t1) */ count(*) +FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +count(*) +10 +explain extended SELECT /*+ QB_NAME(q1) JOIN_ORDER(@q1 t2, t3, t1) */ count(*) +FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t5 ALL PRIMARY NULL NULL NULL 1 100.00 +1 PRIMARY t2 hash_ALL NULL #hash#$hj 4 test.t5.f1 20 11.11 Using where; Using join buffer (flat, BNLH join) +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 100.00 Using join buffer (incremental, BNL join) +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (incremental, BNL join) +1 PRIMARY t4 hash_ALL NULL #hash#$hj 4 test.t1.f1 2 50.00 Using where; FirstMatch(t1); Using join buffer (incremental, BNLH join) +Warnings: +Note 1003 select /*+ QB_NAME(`q1`) JOIN_ORDER(@`q1` `t2`,`t3`,`t1`) */ count(0) AS `count(*)` from `test`.`t5` semi join (`test`.`t4`) join `test`.`t1` join `test`.`t2` join `test`.`t3` where `test`.`t4`.`f1` = `test`.`t1`.`f1` and `test`.`t2`.`f1` = `test`.`t5`.`f1` +# Alternative syntax +SELECT /*+ QB_NAME(q1) JOIN_PREFIX(@q1 t2, t3, t1) */ count(*) +FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +count(*) +10 +explain extended SELECT /*+ QB_NAME(q1) JOIN_PREFIX(@q1 t2, t3, t1) */ count(*) +FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 20 100.00 +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 100.00 Using join buffer (flat, BNL join) +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (incremental, BNL join) +1 PRIMARY t5 ALL PRIMARY NULL NULL NULL 1 100.00 Using where; Using join buffer (incremental, BNL join) +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 100.00 +2 MATERIALIZED t4 ALL NULL NULL NULL NULL 2 100.00 +Warnings: +Note 1003 select /*+ QB_NAME(`q1`) JOIN_PREFIX(@`q1` `t2`,`t3`,`t1`) */ count(0) AS `count(*)` from `test`.`t5` semi join (`test`.`t4`) join `test`.`t1` join `test`.`t2` join `test`.`t3` where `test`.`t5`.`f1` = `test`.`t2`.`f1` +# Alternative syntax +SELECT /*+ QB_NAME(q1) JOIN_SUFFIX(@q1 t2, t3, t1) */ count(*) +FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +count(*) +10 +explain extended SELECT /*+ QB_NAME(q1) JOIN_SUFFIX(@q1 t2, t3, t1) */ count(*) +FROM t1 JOIN t2 JOIN t3 +WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) +AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t5 ALL PRIMARY NULL NULL NULL 1 100.00 +1 PRIMARY t4 ALL NULL NULL NULL NULL 2 100.00 Start temporary; Using join buffer (flat, BNL join) +1 PRIMARY t2 hash_ALL NULL #hash#$hj 4 test.t5.f1 20 11.11 Using where; Using join buffer (incremental, BNLH join) +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 100.00 Using join buffer (incremental, BNL join) +1 PRIMARY t1 hash_ALL NULL #hash#$hj 4 test.t4.f1 3 16.67 Using where; End temporary; Using join buffer (incremental, BNLH join) +Warnings: +Note 1003 select /*+ QB_NAME(`q1`) JOIN_SUFFIX(@`q1` `t2`,`t3`,`t1`) */ count(0) AS `count(*)` from `test`.`t5` semi join (`test`.`t4`) join `test`.`t1` join `test`.`t2` join `test`.`t3` where `test`.`t1`.`f1` = `test`.`t4`.`f1` and `test`.`t2`.`f1` = `test`.`t5`.`f1` +DROP TABLE t1, t2, t3, t4 ,t5, t6; +# Testing embedded join +CREATE TABLE t1 (f1 INT); +CREATE TABLE t2 (f1 INT); +CREATE TABLE t3 (f1 INT); +CREATE TABLE t4 (f1 INT); +EXPLAIN EXTENDED SELECT /*+ JOIN_ORDER(t2, t4, t1) */ 1 FROM t1 +JOIN t2 ON 1 +RIGHT JOIN t3 ON 1 +JOIN t4 ON 1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t3 ALL NULL NULL NULL NULL 1 100.00 +1 SIMPLE t1 ALL NULL NULL NULL NULL 1 100.00 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t2 ALL NULL NULL NULL NULL 1 100.00 Using join buffer (incremental, BNL join) +1 SIMPLE t4 ALL NULL NULL NULL NULL 1 100.00 Using join buffer (incremental, BNL join) +Warnings: +Warning 4210 Hint JOIN_ORDER(`t2`,`t4`,`t1`) is ignored as conflicting/duplicated +Note 1003 select 1 AS `1` from `test`.`t3` left join (`test`.`t1` join `test`.`t2`) on(1 and 1) join `test`.`t4` where 1 +EXPLAIN EXTENDED SELECT /*+ JOIN_ORDER(t2, t1, t4) */ 1 FROM t1 +JOIN t2 ON 1 +RIGHT JOIN t3 ON 1 +JOIN t4 ON 1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t3 ALL NULL NULL NULL NULL 1 100.00 +1 SIMPLE t2 ALL NULL NULL NULL NULL 1 100.00 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t1 ALL NULL NULL NULL NULL 1 100.00 Using join buffer (incremental, BNL join) +1 SIMPLE t4 ALL NULL NULL NULL NULL 1 100.00 Using join buffer (incremental, BNL join) +Warnings: +Note 1003 select /*+ JOIN_ORDER(@`select#1` `t2`,`t1`,`t4`) */ 1 AS `1` from `test`.`t3` left join (`test`.`t1` join `test`.`t2`) on(1 and 1) join `test`.`t4` where 1 +EXPLAIN EXTENDED SELECT /*+ JOIN_ORDER(t4, t1, t2) */ 1 FROM t1 +JOIN t2 ON 1 +RIGHT JOIN t3 ON 1 +JOIN t4 ON 1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t3 ALL NULL NULL NULL NULL 1 100.00 +1 SIMPLE t4 ALL NULL NULL NULL NULL 1 100.00 Using join buffer (flat, BNL join) +1 SIMPLE t1 ALL NULL NULL NULL NULL 1 100.00 Using where; Using join buffer (incremental, BNL join) +1 SIMPLE t2 ALL NULL NULL NULL NULL 1 100.00 Using join buffer (incremental, BNL join) +Warnings: +Note 1003 select /*+ JOIN_ORDER(@`select#1` `t4`,`t1`,`t2`) */ 1 AS `1` from `test`.`t3` left join (`test`.`t1` join `test`.`t2`) on(1 and 1) join `test`.`t4` where 1 +EXPLAIN EXTENDED SELECT /*+ JOIN_ORDER(t3, t4) */ 1 FROM t1 +JOIN t2 ON 1 +RIGHT JOIN t3 ON 1 +JOIN t4 ON 1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t3 ALL NULL NULL NULL NULL 1 100.00 +1 SIMPLE t1 ALL NULL NULL NULL NULL 1 100.00 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t2 ALL NULL NULL NULL NULL 1 100.00 Using join buffer (incremental, BNL join) +1 SIMPLE t4 ALL NULL NULL NULL NULL 1 100.00 Using join buffer (incremental, BNL join) +Warnings: +Note 1003 select /*+ JOIN_ORDER(@`select#1` `t3`,`t4`) */ 1 AS `1` from `test`.`t3` left join (`test`.`t1` join `test`.`t2`) on(1 and 1) join `test`.`t4` where 1 +EXPLAIN SELECT /*+ JOIN_ORDER(t4, t3) */ 1 FROM t1 +JOIN t2 ON 1 +RIGHT JOIN t3 ON 1 +JOIN t4 ON 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t4 ALL NULL NULL NULL NULL 1 +1 SIMPLE t3 ALL NULL NULL NULL NULL 1 Using join buffer (flat, BNL join) +1 SIMPLE t1 ALL NULL NULL NULL NULL 1 Using where; Using join buffer (incremental, BNL join) +1 SIMPLE t2 ALL NULL NULL NULL NULL 1 Using join buffer (incremental, BNL join) +EXPLAIN EXTENDED SELECT /*+ JOIN_SUFFIX(t1) */ 1 FROM t1 +JOIN t2 ON 1 +RIGHT JOIN t3 ON 1 +JOIN t4 ON 1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t3 ALL NULL NULL NULL NULL 1 100.00 +1 SIMPLE t4 ALL NULL NULL NULL NULL 1 100.00 Using join buffer (flat, BNL join) +1 SIMPLE t2 ALL NULL NULL NULL NULL 1 100.00 Using where; Using join buffer (incremental, BNL join) +1 SIMPLE t1 ALL NULL NULL NULL NULL 1 100.00 Using join buffer (incremental, BNL join) +Warnings: +Note 1003 select /*+ JOIN_SUFFIX(@`select#1` `t1`) */ 1 AS `1` from `test`.`t3` left join (`test`.`t1` join `test`.`t2`) on(1 and 1) join `test`.`t4` where 1 +EXPLAIN EXTENDED SELECT /*+ JOIN_SUFFIX(t2, t1) */ 1 FROM t1 +JOIN t2 ON 1 +RIGHT JOIN t3 ON 1 +JOIN t4 ON 1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t3 ALL NULL NULL NULL NULL 1 100.00 +1 SIMPLE t4 ALL NULL NULL NULL NULL 1 100.00 Using join buffer (flat, BNL join) +1 SIMPLE t2 ALL NULL NULL NULL NULL 1 100.00 Using where; Using join buffer (incremental, BNL join) +1 SIMPLE t1 ALL NULL NULL NULL NULL 1 100.00 Using join buffer (incremental, BNL join) +Warnings: +Note 1003 select /*+ JOIN_SUFFIX(@`select#1` `t2`,`t1`) */ 1 AS `1` from `test`.`t3` left join (`test`.`t1` join `test`.`t2`) on(1 and 1) join `test`.`t4` where 1 +DROP TABLE t1, t2, t3, t4; +CREATE TABLE t1 +( +f1 INT(11) NOT NULL AUTO_INCREMENT, +PRIMARY KEY (f1) +); +INSERT INTO t1 VALUES (1),(2),(3); +CREATE TABLE t2 +( +f1 INT(11) DEFAULT NULL +); +INSERT INTO t2 VALUES (0),(1),(2); +CREATE TABLE t3 +( +f1 INT(11) DEFAULT NULL +); +INSERT INTO t3 VALUES (0),(1),(2); +# Original query +EXPLAIN EXTENDED DELETE +FROM ta1.* USING t1 AS ta1 JOIN t1 AS ta2 ON 1 +RIGHT OUTER JOIN t2 ON (ta1.f1 = t2.f1) +WHERE (9) IN (SELECT f1 FROM t3); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 3 33.33 Using where; Start temporary; End temporary +1 PRIMARY t2 ALL NULL NULL NULL NULL 3 100.00 +1 PRIMARY ta1 eq_ref PRIMARY PRIMARY 4 test.t2.f1 1 100.00 Using where +1 PRIMARY ta2 ALL NULL NULL NULL NULL 3 100.00 +Warnings: +Note 1003 delete from `test`.`t1` `ta1` using `test`.`t2` semi join (`test`.`t3`) left join (`test`.`t1` `ta1` join `test`.`t1` `ta2`) on(`test`.`ta1`.`f1` = `test`.`t2`.`f1` and 1 and `test`.`t2`.`f1` is not null) where `test`.`t3`.`f1` = 9 +# Applicable hint +EXPLAIN EXTENDED DELETE /*+ JOIN_PREFIX(t2, t3, ta2) */ +FROM ta1.* USING t1 AS ta1 JOIN t1 AS ta2 ON 1 +RIGHT OUTER JOIN t2 ON (ta1.f1 = t2.f1) +WHERE (9) IN (SELECT f1 FROM t3); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 3 100.00 +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 100.00 +1 PRIMARY ta2 ALL NULL NULL NULL NULL 3 100.00 Using where +1 PRIMARY ta1 eq_ref PRIMARY PRIMARY 4 test.t2.f1 1 100.00 +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 delete /*+ JOIN_PREFIX(@`select#1` `t2`,`t3`,`ta2`) */ from `test`.`t1` `ta1` using `test`.`t2` semi join (`test`.`t3`) left join (`test`.`t1` `ta1` join `test`.`t1` `ta2`) on(`test`.`ta1`.`f1` = `test`.`t2`.`f1` and 1 and `test`.`t2`.`f1` is not null) where `test`.`t3`.`f1` = 9 +# Applicable hint +EXPLAIN EXTENDED DELETE /*+ JOIN_PREFIX(t2, t3, ta1, ta2) */ +FROM ta1.* USING t1 AS ta1 JOIN t1 AS ta2 ON 1 +RIGHT OUTER JOIN t2 ON (ta1.f1 = t2.f1) +WHERE (9) IN (SELECT f1 FROM t3); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 3 100.00 +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 100.00 +1 PRIMARY ta1 eq_ref PRIMARY PRIMARY 4 test.t2.f1 1 100.00 Using where +1 PRIMARY ta2 ALL NULL NULL NULL NULL 3 100.00 +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 delete /*+ JOIN_PREFIX(@`select#1` `t2`,`t3`,`ta1`,`ta2`) */ from `test`.`t1` `ta1` using `test`.`t2` semi join (`test`.`t3`) left join (`test`.`t1` `ta1` join `test`.`t1` `ta2`) on(`test`.`ta1`.`f1` = `test`.`t2`.`f1` and 1 and `test`.`t2`.`f1` is not null) where `test`.`t3`.`f1` = 9 +# Applicable hint +EXPLAIN EXTENDED DELETE /*+ JOIN_PREFIX(t2, t3, ta2, ta1) */ +FROM ta1.* USING t1 AS ta1 JOIN t1 AS ta2 ON 1 +RIGHT OUTER JOIN t2 ON (ta1.f1 = t2.f1) +WHERE (9) IN (SELECT f1 FROM t3); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 3 100.00 +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 100.00 +1 PRIMARY ta2 ALL NULL NULL NULL NULL 3 100.00 Using where +1 PRIMARY ta1 eq_ref PRIMARY PRIMARY 4 test.t2.f1 1 100.00 +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 delete /*+ JOIN_PREFIX(@`select#1` `t2`,`t3`,`ta2`,`ta1`) */ from `test`.`t1` `ta1` using `test`.`t2` semi join (`test`.`t3`) left join (`test`.`t1` `ta1` join `test`.`t1` `ta2`) on(`test`.`ta1`.`f1` = `test`.`t2`.`f1` and 1 and `test`.`t2`.`f1` is not null) where `test`.`t3`.`f1` = 9 +# Hint should be ignored +EXPLAIN EXTENDED DELETE /*+ JOIN_SUFFIX(ta2, t3, ta1) */ +FROM ta1.* USING t1 AS ta1 JOIN t1 AS ta2 ON 1 +RIGHT OUTER JOIN t2 ON (ta1.f1 = t2.f1) +WHERE (9) IN (SELECT f1 FROM t3); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 3 33.33 Using where; Start temporary; End temporary +1 PRIMARY t2 ALL NULL NULL NULL NULL 3 100.00 +1 PRIMARY ta1 eq_ref PRIMARY PRIMARY 4 test.t2.f1 1 100.00 Using where +1 PRIMARY ta2 ALL NULL NULL NULL NULL 3 100.00 +Warnings: +Warning 4210 Hint JOIN_SUFFIX(`ta2`,`t3`,`ta1`) is ignored as conflicting/duplicated +Note 1003 delete from `test`.`t1` `ta1` using `test`.`t2` semi join (`test`.`t3`) left join (`test`.`t1` `ta1` join `test`.`t1` `ta2`) on(`test`.`ta1`.`f1` = `test`.`t2`.`f1` and 1 and `test`.`t2`.`f1` is not null) where `test`.`t3`.`f1` = 9 +# Both hints are ignored +EXPLAIN EXTENDED DELETE /*+ JOIN_PREFIX(ta1, t2, t3) JOIN_SUFFIX(t3, ta2) */ +FROM ta1.* USING t1 AS ta1 JOIN t1 AS ta2 ON 1 +RIGHT OUTER JOIN t2 ON (ta1.f1 = t2.f1) +WHERE (9) IN (SELECT f1 FROM t3); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 3 33.33 Using where; Start temporary; End temporary +1 PRIMARY t2 ALL NULL NULL NULL NULL 3 100.00 +1 PRIMARY ta1 eq_ref PRIMARY PRIMARY 4 test.t2.f1 1 100.00 Using where +1 PRIMARY ta2 ALL NULL NULL NULL NULL 3 100.00 +Warnings: +Warning 4210 Hint JOIN_PREFIX(`ta1`,`t2`,`t3`) is ignored as conflicting/duplicated +Warning 4210 Hint JOIN_SUFFIX(`t3`,`ta2`) is ignored as conflicting/duplicated +Note 1003 delete from `test`.`t1` `ta1` using `test`.`t2` semi join (`test`.`t3`) left join (`test`.`t1` `ta1` join `test`.`t1` `ta2`) on(`test`.`ta1`.`f1` = `test`.`t2`.`f1` and 1 and `test`.`t2`.`f1` is not null) where `test`.`t3`.`f1` = 9 +DROP TABLE t1, t2, t3; +# Const table behavior, table order is not changed, hint is applicable. +# Note: Const tables are excluded from the process of dependency setting +# since they are always first in the table order. Note that it +# does not prevent the hint from being applied to the non-const +# tables of the hint. +CREATE TABLE t1(f1 INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1); +CREATE TABLE t2(f1 INT) ENGINE=InnoDB; +INSERT INTO t2 VALUES (1); +EXPLAIN EXTENDED SELECT /*+ JOIN_PREFIX(t1, t2) */ 1 FROM t1 JOIN t2 ON t1.f1 = t2.f1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 system NULL NULL NULL NULL 1 100.00 +1 SIMPLE t2 ALL NULL NULL NULL NULL 1 100.00 Using where +Warnings: +Note 1003 select /*+ JOIN_PREFIX(@`select#1` `t1`,`t2`) */ 1 AS `1` from `test`.`t2` where `test`.`t2`.`f1` = 1 +EXPLAIN EXTENDED SELECT /*+ JOIN_PREFIX(t2, t1) */ 1 FROM t1 JOIN t2 ON t1.f1 = t2.f1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 system NULL NULL NULL NULL 1 100.00 +1 SIMPLE t2 ALL NULL NULL NULL NULL 1 100.00 Using where +Warnings: +Note 1003 select /*+ JOIN_PREFIX(@`select#1` `t2`,`t1`) */ 1 AS `1` from `test`.`t2` where `test`.`t2`.`f1` = 1 +DROP TABLE t1, t2; +# +# Bug#23144274 WL9158:ASSERTION `JOIN->BEST_READ < DOUBLE(1.79769313486231570815E+308L)' FAILED +# +CREATE TABLE t1 ( +f1 int(11) NOT NULL AUTO_INCREMENT, +f2 varchar(255) DEFAULT NULL, +PRIMARY KEY (f1)); +CREATE TABLE t2 ( +f1 int(11) NOT NULL AUTO_INCREMENT, +f2 varchar(255) CHARACTER SET utf8mb3 DEFAULT NULL, +f3 varchar(10) DEFAULT NULL, +PRIMARY KEY (f1), +KEY f3(f3)); +EXPLAIN SELECT /*+ JOIN_SUFFIX(t1, t2) */ t2.f3 FROM t2 LEFT JOIN t1 +ON t2.f1 = t1.f1 WHERE t1.f2 NOT LIKE ('FMGAU') OR t2.f2 > 't'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 1 +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.f1 1 Using where +Warnings: +Warning 4210 Hint JOIN_SUFFIX(`t1`,`t2`) is ignored as conflicting/duplicated +DROP TABLE t1, t2; +CREATE TABLE t1 +( +f1 int(11) DEFAULT NULL, +KEY f1 (f1) +); +CREATE TABLE t2 +( +f1 int(11) DEFAULT NULL, +f2 varchar(255) CHARACTER SET utf8mb3 DEFAULT NULL, +KEY f2 (f2), +KEY f1 (f1) +); +CREATE TABLE t3 ( +f1 int(11) DEFAULT NULL, +f2 varchar(255) CHARACTER SET cp932 DEFAULT NULL, +KEY f1 (f1), +KEY f2 (f2) +); +EXPLAIN EXTENDED SELECT /*+ JOIN_ORDER(t2, t3) JOIN_ORDER(t1, t2) */ t3.f1 +FROM ( t2 INNER JOIN t3 ON t3.f2 = t2.f2 LEFT JOIN t1 ON t1.f1 = t3.f1 ) +WHERE NOT (t2.f1 >= 7); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 range f2,f1 f1 5 NULL 1 100.00 Using index condition +1 SIMPLE t3 ALL NULL NULL NULL NULL 1 100.00 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t1 ref f1 f1 5 test.t3.f1 1 100.00 Using where; Using index +Warnings: +Warning 4210 Hint JOIN_ORDER(`t1`,`t2`) is ignored as conflicting/duplicated +Note 1003 select /*+ JOIN_ORDER(@`select#1` `t2`,`t3`) */ `test`.`t3`.`f1` AS `f1` from `test`.`t2` join `test`.`t3` left join `test`.`t1` on(`test`.`t1`.`f1` = `test`.`t3`.`f1` and `test`.`t3`.`f1` is not null) where `test`.`t2`.`f1` < 7 and convert(`test`.`t3`.`f2` using utf8mb3) = `test`.`t2`.`f2` +EXPLAIN EXTENDED SELECT /*+ JOIN_ORDER(t1, t2) JOIN_ORDER(t2, t3) */ t3.f1 +FROM ( t2 INNER JOIN t3 ON t3.f2 = t2.f2 LEFT JOIN t1 ON t1.f1 = t3.f1 ) +WHERE NOT (t2.f1 >= 7); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t3 ALL NULL NULL NULL NULL 1 100.00 +1 SIMPLE t1 ref f1 f1 5 test.t3.f1 1 100.00 Using where; Using index +1 SIMPLE t2 ref f2,f1 f2 768 func 1 100.00 Using index condition; Using where +Warnings: +Warning 4210 Hint JOIN_ORDER(`t2`,`t3`) is ignored as conflicting/duplicated +Note 1003 select /*+ JOIN_ORDER(@`select#1` `t1`,`t2`) */ `test`.`t3`.`f1` AS `f1` from `test`.`t2` join `test`.`t3` left join `test`.`t1` on(`test`.`t1`.`f1` = `test`.`t3`.`f1` and `test`.`t3`.`f1` is not null) where `test`.`t2`.`f1` < 7 and convert(`test`.`t3`.`f2` using utf8mb3) = `test`.`t2`.`f2` +DROP TABLE t1, t2, t3; +CREATE TABLE t1 ( +f1 INT(11) NOT NULL AUTO_INCREMENT, +f2 INT(11) DEFAULT NULL, +PRIMARY KEY (f1) +); +CREATE TABLE t2 ( +f1 INT(11) NOT NULL AUTO_INCREMENT, +PRIMARY KEY (f1) +); +EXPLAIN EXTENDED SELECT /*+ JOIN_PREFIX(t1, t1) */ t2.f1 FROM t1 JOIN t2 ON t1.f2 = t2.f1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 1 100.00 Using where +1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.f2 1 100.00 +Warnings: +Warning 4210 Hint JOIN_PREFIX(`t1`,`t1`) is ignored as conflicting/duplicated +Note 1003 select `test`.`t2`.`f1` AS `f1` from `test`.`t1` join `test`.`t2` where `test`.`t2`.`f1` = `test`.`t1`.`f2` +DROP TABLE t1, t2; +CREATE TABLE t1 +( +f1 DATETIME, +f2 DATE, +f3 VARCHAR(1), +KEY (f1) +) ENGINE=myisam; +CREATE TABLE t2 +( +f1 VARCHAR(1), +f2 INT, +f3 VARCHAR(1), +KEY (f1) +) ENGINE=innodb; +CREATE TABLE t3 +( +f1 VARCHAR(1), +f2 DATE, +f3 DATETIME, +f4 INT +) ENGINE=myisam; +EXPLAIN EXTENDED +UPDATE /*+ JOIN_ORDER(t2, als1, als3) JOIN_FIXED_ORDER() */ t3 AS als1 +JOIN t1 AS als2 ON (als1.f3 = als2 .f1) +JOIN t1 AS als3 ON (als1.f1 = als3.f3) +RIGHT OUTER JOIN t3 AS als4 ON (als1.f3 = als4.f2) +SET als1.f4 = 'eogqjvbhzodzimqahyzlktkbexkhdwxwgifikhcgblhgswxyutepc' +WHERE ('i','b') IN (SELECT f3, f1 FROM t2 WHERE f2 <> f2 AND als2.f2 IS NULL); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +Warnings: +Warning 4210 Hint JOIN_FIXED_ORDER() is ignored as conflicting/duplicated +Note 1276 Field or reference 'test.als2.f2' of SELECT #2 was resolved in SELECT #1 +Note 1003 update /*+ JOIN_ORDER(@`select#1` `t2`,`als1`,`als3`) */ (`test`.`t2`) join `test`.`t3` `als4` left join (`test`.`t3` `als1` join `test`.`t1` `als2` join `test`.`t1` `als3`) on(`test`.`als1`.`f3` = `test`.`als4`.`f2` and multiple equal(`test`.`als1`.`f1`, `test`.`als3`.`f3`) and multiple equal(`test`.`als1`.`f3`, `test`.`als2`.`f1`)) set `test`.`als1`.`f4` = 'eogqjvbhzodzimqahyzlktkbexkhdwxwgifikhcgblhgswxyutepc' where 0 +DROP TABLE t1, t2, t3; +CREATE TABLE t1( +f1 VARCHAR(1)) ENGINE=myisam; +CREATE TABLE t2( +f1 VARCHAR(1), +f2 VARCHAR(1), +f3 DATETIME, +KEY(f2)) ENGINE=innodb; +CREATE TABLE t3( +f1 INT, +f2 DATE, +f3 VARCHAR(1), +KEY(f3)) ENGINE=myisam; +CREATE TABLE t4( +f1 VARCHAR(1), +KEY(f1)) ENGINE=innodb; +ALTER TABLE t4 DISABLE KEYS; +Warnings: +Note 1031 Storage engine InnoDB of the table `test`.`t4` doesn't have this option +INSERT INTO t4 VALUES ('x'), (NULL), ('d'), ('x'), ('u'); +ALTER TABLE t4 ENABLE KEYS; +Warnings: +Note 1031 Storage engine InnoDB of the table `test`.`t4` doesn't have this option +CREATE TABLE t5( +f1 VARCHAR(1), +KEY(f1) ) ENGINE=myisam; +INSERT INTO t5 VALUES (NULL), ('s'), ('c'), ('x'), ('z'); +EXPLAIN EXTENDED UPDATE /*+ JOIN_ORDER(t4, alias1, alias3) */ t3 AS alias1 +JOIN t5 ON (alias1.f3 = t5.f1) +JOIN t3 AS alias3 ON (alias1.f2 = alias3.f2 ) +RIGHT OUTER JOIN t1 ON (alias1.f3 = t1.f1) +SET alias1.f1 = -1 +WHERE ( 'v', 'o' ) IN +(SELECT DISTINCT t2.f1, t2.f2 FROM t4 RIGHT OUTER JOIN t2 ON (t4.f1 = t2.f1) +WHERE t2.f3 BETWEEN '2001-10-04' AND '2003-05-15'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +Warnings: +Note 1003 update /*+ JOIN_ORDER(@`select#1` `t4`,`alias1`,`alias3`) */ `test`.`t1` semi join (`test`.`t2` left join `test`.`t4` on(`test`.`t4`.`f1` = `test`.`t2`.`f1` and `test`.`t2`.`f1` is not null)) left join (`test`.`t3` `alias1` join `test`.`t5` join `test`.`t3` `alias3`) on(`test`.`alias1`.`f3` = NULL and `test`.`t5`.`f1` = NULL and `test`.`alias3`.`f2` = `test`.`alias1`.`f2` and NULL is not null and `test`.`alias1`.`f2` is not null and NULL is not null) set `test`.`alias1`.`f1` = -1 where 0 +DROP TABLE t1, t2, t3, t4, t5; +CREATE TABLE t1 ( +f1 INT(11) DEFAULT NULL, +f3 VARCHAR(1) DEFAULT NULL, +f2 INT(11) DEFAULT NULL, +KEY (f1) +) ENGINE=MyISAM; +CREATE TABLE t2( +f1 INT(11) DEFAULT NULL +) ENGINE=MyISAM; +CREATE TABLE t3 ( +f1 VARCHAR(1) DEFAULT NULL, +f2 VARCHAR(1) DEFAULT NULL, +KEY (f2) +) ENGINE=InnoDB; +EXPLAIN EXTENDED UPDATE /*+ JOIN_SUFFIX(ta1, t2) */ +t1 AS ta1 JOIN t1 AS ta2 ON ta1.f1 = ta2.f1 RIGHT JOIN t2 ON (ta1.f1 = t2.f1) +SET ta1.f2 = '', ta2.f3 = '' +WHERE ('n', 'r') IN (SELECT f2, f1 FROM t3 WHERE f1 <> f2 XOR ta2.f3 IS NULL); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +Warnings: +Note 1276 Field or reference 'test.ta2.f3' of SELECT #2 was resolved in SELECT #1 +Note 1003 update /*+ JOIN_SUFFIX(@`select#1` `ta1`,`t2`) */ `test`.`t2` semi join (`test`.`t3`) left join (`test`.`t1` `ta1` join `test`.`t1` `ta2`) on(`test`.`ta2`.`f1` = NULL and `test`.`ta1`.`f1` = NULL and NULL is not null and NULL is not null) set `test`.`ta1`.`f2` = '',`test`.`ta2`.`f3` = '' where 0 +DROP TABLE t1, t2, t3; +CREATE TABLE t2(f1 VARCHAR(255) DEFAULT NULL, f2 INT(11) DEFAULT NULL, +KEY (f1), KEY (f2)) charset latin1 ENGINE=MyISAM; +CREATE TABLE t4(f1 INT(11) DEFAULT NULL, f2 INT(11) DEFAULT NULL, KEY (f1)) +charset latin1 ENGINE=MyISAM; +CREATE TABLE t5(f1 INT(11) NOT NULL AUTO_INCREMENT, f2 INT(11) DEFAULT NULL, PRIMARY KEY (f1)) +charset latin1 ENGINE=InnoDB; +CREATE TABLE t6(f1 INT(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (f1)) +charset latin1 ENGINE=InnoDB; +CREATE TABLE t7 (f1 VARCHAR(255) DEFAULT NULL) +charset latin1 ENGINE=InnoDB; +CREATE TABLE t10(f1 INT(11) NOT NULL AUTO_INCREMENT,f2 INT(11) DEFAULT NULL,f3 VARCHAR(10) DEFAULT NULL, +PRIMARY KEY (f1),KEY (f2),KEY (f3)) charset latin1 ENGINE=MyISAM; +CREATE TABLE t11(f1 INT(11) DEFAULT NULL,f2 VARCHAR(10) DEFAULT NULL, +KEY (f1),KEY (f2)) charset latin1 ENGINE=InnoDB; +EXPLAIN EXTENDED +SELECT /*+ JOIN_ORDER(alias11, alias8) */ 1 +FROM t4 AS alias4 +LEFT JOIN t5 AS alias5 JOIN t6 AS alias6 ON alias5.f2 = alias6.f1 +LEFT JOIN t7 AS alias7 JOIN t2 AS alias8 ON alias7.f1 = alias8.f1 +ON alias5.f1 = alias8.f2 ON alias4.f2 = alias6.f1 +JOIN t10 AS alias10 JOIN t11 AS alias11 ON alias10.f1 = alias11.f1 +ON alias4.f2 = alias11.f2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +Warnings: +Note 1105 Cannot use key `f2` part[0] for lookup: `test`.`t11`.`f2` of type `varchar` = "`alias4`.`f2`" of type `int` +Note 1003 select /*+ JOIN_ORDER(@`select#1` `alias11`,`alias8`) */ 1 AS `1` from `test`.`t4` `alias4` left join (`test`.`t5` `alias5` join `test`.`t6` `alias6` left join (`test`.`t7` `alias7` join `test`.`t2` `alias8`) on(`test`.`alias8`.`f2` = `test`.`alias5`.`f1` and `test`.`alias8`.`f1` = `test`.`alias7`.`f1` and `test`.`alias7`.`f1` is not null)) on(`test`.`alias5`.`f2` = NULL and `test`.`alias6`.`f1` = NULL and NULL is not null and `test`.`alias5`.`f2` is not null) join `test`.`t10` `alias10` join `test`.`t11` `alias11` where 0 +EXPLAIN EXTENDED +SELECT /*+ JOIN_ORDER(alias11, alias10, alias8, alias7) */ 1 +FROM t4 AS alias4 +LEFT JOIN t5 AS alias5 JOIN t6 AS alias6 ON alias5.f2 = alias6.f1 +LEFT JOIN t7 AS alias7 JOIN t2 AS alias8 ON alias7.f1 = alias8.f1 +ON alias5.f1 = alias8.f2 ON alias4.f2 = alias6.f1 +JOIN t10 AS alias10 JOIN t11 AS alias11 ON alias10.f1 = alias11.f1 +ON alias4.f2 = alias11.f2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +Warnings: +Note 1105 Cannot use key `f2` part[0] for lookup: `test`.`t11`.`f2` of type `varchar` = "`alias4`.`f2`" of type `int` +Note 1003 select /*+ JOIN_ORDER(@`select#1` `alias11`,`alias10`,`alias8`,`alias7`) */ 1 AS `1` from `test`.`t4` `alias4` left join (`test`.`t5` `alias5` join `test`.`t6` `alias6` left join (`test`.`t7` `alias7` join `test`.`t2` `alias8`) on(`test`.`alias8`.`f2` = `test`.`alias5`.`f1` and `test`.`alias7`.`f1` = `test`.`alias8`.`f1` and `test`.`alias5`.`f1` is not null and `test`.`alias8`.`f1` is not null)) on(`test`.`alias5`.`f2` = NULL and `test`.`alias6`.`f1` = NULL and NULL is not null and `test`.`alias5`.`f2` is not null) join `test`.`t10` `alias10` join `test`.`t11` `alias11` where 0 +DROP TABLES t2, t4, t5, t6, t7, t10, t11; +CREATE TABLE t1 (f1 VARCHAR(255) DEFAULT NULL, f2 VARCHAR(255) DEFAULT NULL, +KEY (f1), KEY (f2)) ENGINE=InnoDB; +CREATE TABLE t2(f1 VARCHAR(255) DEFAULT NULL, f2 INT(11) DEFAULT NULL, +KEY (f1), KEY (f2)) ENGINE=InnoDB; +CREATE TABLE t3( +f1 INT(11) NOT NULL AUTO_INCREMENT, f2 VARCHAR(255) DEFAULT NULL, +PRIMARY KEY (f1), KEY (f2)) ENGINE=InnoDB; +CREATE TABLE t4(f1 INT(11) DEFAULT NULL, f2 INT(11) DEFAULT NULL, KEY (f1)) ENGINE=InnoDB; +CREATE TABLE t6(f1 INT(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (f1)) ENGINE=InnoDB; +CREATE TABLE t7 (f1 VARCHAR(255) DEFAULT NULL) ENGINE=InnoDB; +CREATE TABLE t10(f1 INT(11) NOT NULL AUTO_INCREMENT,f2 INT(11) DEFAULT NULL,f3 VARCHAR(10) DEFAULT NULL, +PRIMARY KEY (f1),KEY (f2),KEY (f3)) ENGINE=InnoDB; +EXPLAIN EXTENDED SELECT /*+ JOIN_ORDER(alias8, alias6) */ 1 +FROM t1 AS alias1 +LEFT JOIN t7 alias7 +JOIN t2 AS alias2 +LEFT JOIN t3 AS alias3 JOIN t4 AS alias4 ON alias4.f2 = alias3.f1 +ON alias4.f1 = alias2.f1 +ON alias2.f2 = alias7.f1 +JOIN t10 AS alias5 +LEFT JOIN t6 AS alias6 JOIN t2 AS alias8 ON alias6.f1 = alias8.f2 +ON alias6.f1 = alias5.f1 +ON alias5.f3 = alias7.f1 +ON alias1.f2 = alias7.f1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE alias1 index NULL f2 1023 NULL 1 100.00 Using index +1 SIMPLE alias7 ALL NULL NULL NULL NULL 1 10.00 Using where +1 SIMPLE alias2 ref f2 f2 5 test.alias7.f1 1 100.00 Using where +1 SIMPLE alias4 ref f1 f1 5 test.alias2.f1 1 100.00 Using where +1 SIMPLE alias3 eq_ref PRIMARY PRIMARY 4 test.alias4.f2 1 100.00 +1 SIMPLE alias5 ref f3 f3 43 test.alias7.f1 1 100.00 Using where; Using index +1 SIMPLE alias8 ref f2 f2 5 test.alias5.f1 1 100.00 Using where; Using index +1 SIMPLE alias6 eq_ref PRIMARY PRIMARY 4 test.alias8.f2 1 100.00 Using where +Warnings: +Note 1003 select /*+ JOIN_ORDER(@`select#1` `alias8`,`alias6`) */ 1 AS `1` from `test`.`t1` `alias1` left join (`test`.`t7` `alias7` join `test`.`t2` `alias2` left join (`test`.`t3` `alias3` join `test`.`t4` `alias4`) on(`test`.`alias3`.`f1` = `test`.`alias4`.`f2` and `test`.`alias4`.`f1` = `test`.`alias2`.`f1` and `test`.`alias2`.`f1` is not null and `test`.`alias4`.`f2` is not null) join `test`.`t10` `alias5` left join (`test`.`t6` `alias6` join `test`.`t2` `alias8`) on(`test`.`alias8`.`f2` = `test`.`alias5`.`f1` and `test`.`alias6`.`f1` = `test`.`alias5`.`f1` and `test`.`alias5`.`f1` is not null and `test`.`alias8`.`f2` is not null)) on(`test`.`alias7`.`f1` = `test`.`alias1`.`f2` and `test`.`alias5`.`f3` = `test`.`alias1`.`f2` and `test`.`alias2`.`f2` = `test`.`alias7`.`f1` and `test`.`alias1`.`f2` is not null and `test`.`alias7`.`f1` is not null and `test`.`alias7`.`f1` is not null) where 1 +DROP TABLES t1, t2, t3, t4, t6, t7, t10; +# +# Bug#23144230 WL#9158 : OPT_HINTS_QB::APPLY_JOIN_ORDER_HINTS - MYSQLD GOT SIGNAL 11 +# +CREATE TABLE t1 ( +f1 int(11) NOT NULL AUTO_INCREMENT, +f2 int(11) DEFAULT NULL, +f3 int(11) DEFAULT NULL, +PRIMARY KEY (f1), +KEY f2 (f2)) +ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1; +CREATE TABLE t2 ( +f1 int(11) NOT NULL AUTO_INCREMENT, +f2 int(11) DEFAULT NULL, +f3 int(11) DEFAULT NULL, +PRIMARY KEY (f1), +KEY f2 (f2)) +ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1; +EXPLAIN EXTENDED SELECT /*+ JOIN_PREFIX(alias1) */ alias2.f3 AS field1 +FROM ( SELECT * FROM t1 ) AS alias1 JOIN ( SELECT * FROM t2 ) AS alias2 +ON alias1.f2 = alias2.f3 +WHERE alias2.f2 IS NULL HAVING (field1 != 3 AND field1 >= 8); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 ref f2 f2 5 const 1 100.00 Using index condition; Using where +1 SIMPLE t1 ref f2 f2 5 test.t2.f3 1 100.00 Using index +Warnings: +Warning 4212 Unresolved table name `alias1` for JOIN_PREFIX hint +Note 1003 select `test`.`t2`.`f3` AS `field1` from `test`.`t1` join `test`.`t2` where `test`.`t1`.`f2` = `test`.`t2`.`f3` and `test`.`t2`.`f2` is null having `f3` <> 3 and `f3` >= 8 +DROP TABLE t1, t2; +# +# Bug#23651098 WL#9158 : ASSERTION `!(SJ_NEST->SJ_INNER_TABLES & JOIN->CONST_TABLE_MAP)' FAILED +# +CREATE TABLE t1 +( +f1 INT(11) NOT NULL AUTO_INCREMENT, +PRIMARY KEY (f1) +) ENGINE=InnoDB; +CREATE TABLE t2 +( +f1 VARCHAR(1) DEFAULT NULL +) ENGINE=MyISAM; +CREATE TABLE t3 +( +f1 VARCHAR(1) DEFAULT NULL +) ENGINE=MyISAM; +EXPLAIN EXTENDED SELECT /*+ JOIN_PREFIX(t2, t1) */ t1.f1 FROM t1, t2 +WHERE t2.f1 IN (SELECT t3.f1 FROM t3) AND t1.f1 = 183; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +Warnings: +Note 1003 select /*+ JOIN_PREFIX(@`select#1` `t2`,`t1`) */ NULL AS `f1` from `test`.`t1` semi join (`test`.`t3`) join `test`.`t2` where 0 +DROP TABLE t1, t2, t3; +# +# Bug23715779 SELECT QUERY WITH JOIN_PREFIX() HINT RETURNS INCORRECT RESULT +# +CREATE TABLE t1(f1 INT(11) NOT NULL); +INSERT INTO t1 VALUES (10); +CREATE TABLE t2 +( +f1 INT(11) NOT NULL AUTO_INCREMENT, +f2 INT(11) DEFAULT NULL, +PRIMARY KEY (f1), +KEY (f2) +); +INSERT INTO t2 VALUES (1, 7), (2, 1), (4, 7); +CREATE TABLE t4(f1 INT DEFAULT NULL); +INSERT INTO t4 VALUES (2); +ANALYZE TABLE t1, t2, t4; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +test.t2 analyze status Engine-independent statistics collected +test.t2 analyze status OK +test.t4 analyze status Engine-independent statistics collected +test.t4 analyze status OK +SELECT +COUNT(*) FROM t1 JOIN t2 AS ta3 JOIN t2 AS ta4 +WHERE ta4.f1 IN (SELECT /*+ QB_NAME(qb1) */ f1 FROM t4) AND +ta3.f2 IN (SELECT /*+ QB_NAME(qb2) */ f2 FROM t2); +COUNT(*) +3 +explain extended SELECT +COUNT(*) FROM t1 JOIN t2 AS ta3 JOIN t2 AS ta4 +WHERE ta4.f1 IN (SELECT /*+ QB_NAME(qb1) */ f1 FROM t4) AND +ta3.f2 IN (SELECT /*+ QB_NAME(qb2) */ f2 FROM t2); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 1 100.00 +1 PRIMARY t2 index f2 f2 5 NULL 3 100.00 Using where; Using index; LooseScan +1 PRIMARY ta3 ref f2 f2 5 test.t2.f2 1 33.33 Using index +1 PRIMARY ta4 index PRIMARY f2 5 NULL 3 100.00 Using index; Using join buffer (flat, BNL join) +1 PRIMARY t4 hash_ALL NULL #hash#$hj 5 test.ta4.f1 1 100.00 Using where; FirstMatch(ta4); Using join buffer (incremental, BNLH join) +Warnings: +Note 1003 select count(0) AS `COUNT(*)` from `test`.`t1` semi join (`test`.`t4`) semi join (`test`.`t2`) join `test`.`t2` `ta3` join `test`.`t2` `ta4` where `test`.`t4`.`f1` = `test`.`ta4`.`f1` and `test`.`ta3`.`f2` = `test`.`t2`.`f2` +SELECT /*+ JOIN_PREFIX(t2@qb2, t4@qb1, ta3, ta4) */ +COUNT(*) FROM t1 JOIN t2 AS ta3 JOIN t2 AS ta4 +WHERE ta4.f1 IN (SELECT /*+ QB_NAME(qb1) */ f1 FROM t4) AND +ta3.f2 IN (SELECT /*+ QB_NAME(qb2) */ f2 FROM t2); +COUNT(*) +3 +explain extended SELECT /*+ JOIN_PREFIX(t2@qb2, t4@qb1, ta3, ta4) */ +COUNT(*) FROM t1 JOIN t2 AS ta3 JOIN t2 AS ta4 +WHERE ta4.f1 IN (SELECT /*+ QB_NAME(qb1) */ f1 FROM t4) AND +ta3.f2 IN (SELECT /*+ QB_NAME(qb2) */ f2 FROM t2); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index f2 f2 5 NULL 3 100.00 Using where; Using index; Start temporary +1 PRIMARY t4 ALL NULL NULL NULL NULL 1 100.00 Using where; Using join buffer (flat, BNL join) +1 PRIMARY ta3 ref f2 f2 5 test.t2.f2 1 33.33 Using index +1 PRIMARY ta4 eq_ref PRIMARY PRIMARY 4 test.t4.f1 1 33.33 End temporary +1 PRIMARY t1 ALL NULL NULL NULL NULL 1 100.00 Using join buffer (flat, BNL join) +Warnings: +Note 1003 select /*+ JOIN_PREFIX(@`select#1` `t2`@`qb2`,`t4`@`qb1`,`ta3`,`ta4`) */ count(0) AS `COUNT(*)` from `test`.`t1` semi join (`test`.`t4`) semi join (`test`.`t2`) join `test`.`t2` `ta3` join `test`.`t2` `ta4` where `test`.`ta4`.`f1` = `test`.`t4`.`f1` and `test`.`ta3`.`f2` = `test`.`t2`.`f2` +DROP TABLE t1, t2, t4; diff --git a/mysql-test/main/opt_hints_join_order.test b/mysql-test/main/opt_hints_join_order.test new file mode 100644 index 00000000000..fabe20ea1e4 --- /dev/null +++ b/mysql-test/main/opt_hints_join_order.test @@ -0,0 +1,791 @@ +--source include/have_innodb.inc +--enable_prepare_warnings +--disable_view_protocol # Since optimizer hints are not supported inside views + +set default_storage_engine=innodb; + +CREATE TABLE t1 (f1 INT NOT NULL); +INSERT INTO t1 VALUES (9),(0), (7); + +CREATE TABLE t2 (f1 INT NOT NULL); +INSERT INTO t2 VALUES +(5),(3),(0),(3),(1),(0),(1),(7),(1),(0),(0),(8),(4),(9),(0),(2),(0),(8),(5),(1); + +CREATE TABLE t3 (f1 INT NOT NULL); +INSERT INTO t3 VALUES (9),(0), (7), (4), (5); + +CREATE TABLE t4 (f1 INT NOT NULL); +INSERT INTO t4 VALUES (0), (7); + +CREATE TABLE t5 (f1 INT NOT NULL, PRIMARY KEY(f1)); +INSERT INTO t5 VALUES (7); + +CREATE TABLE t6(f1 INT NOT NULL, PRIMARY KEY(f1)); +INSERT INTO t6 VALUES (7); + +ANALYZE TABLE t1, t2, t3, t4, t5, t6; + +set join_cache_level = 8; + +--echo # Warning expected: hint must be ignored as malformed (no table names) +EXPLAIN EXTENDED + SELECT /*+ JOIN_PREFIX()*/ count(*) FROM t1, t2; + +EXPLAIN EXTENDED + SELECT /*+ QB_NAME(q1) JOIN_PREFIX(@q1)*/ count(*) FROM t1, t2; + +--echo # Hint must be ignored as malformed (table names are not allowed for the fixed order) +EXPLAIN EXTENDED + SELECT /*+ JOIN_FIXED_ORDER(t2)*/ count(*) FROM t1, t2; + +--echo # Hint is applied: QB name is allowed for the fixed order +EXPLAIN EXTENDED + SELECT /*+ QB_NAME(qb1) JOIN_FIXED_ORDER(@qb1)*/ count(*) FROM t2, t1; + +--echo # Invalid QB name for the fixed order +EXPLAIN EXTENDED + SELECT /*+ QB_NAME(qb1) JOIN_FIXED_ORDER(@qb3)*/ count(*) FROM t2, t1; + +EXPLAIN EXTENDED + SELECT /*+ JOIN_FIXED_ORDER()*/ STRAIGHT_JOIN count(*) FROM t1, t2; + +--echo # JOIN_FIXED_ORDER() cannot be combined with other join order hints +EXPLAIN EXTENDED + SELECT /*+ JOIN_PREFIX(t2) JOIN_FIXED_ORDER()*/ count(*) FROM t1, t2; + +EXPLAIN EXTENDED + SELECT /*+ JOIN_FIXED_ORDER() JOIN_PREFIX(t2)*/ count(*) FROM t1, t2; + +--echo # Multiple join order hints of same type are not allowed (except JOIN_ORDER()) +EXPLAIN EXTENDED + SELECT /*+ JOIN_PREFIX(t1) JOIN_PREFIX(t2)*/ count(*) FROM t1, t2; + +EXPLAIN EXTENDED + SELECT /*+ JOIN_SUFFIX(t1) JOIN_SUFFIX(t2)*/ count(*) FROM t1, t2; + +--echo # Multiple JOIN_ORDER() hints are applied +EXPLAIN EXTENDED + SELECT /*+ QB_NAME(q1) JOIN_ORDER(t2,t1) JOIN_ORDER(@q1 t3,t2)*/ count(*) + FROM t1, t2, t3; + +--echo # Variation of last syntax +EXPLAIN EXTENDED + SELECT /*+ QB_NAME(q1) JOIN_ORDER(t2@q1, t1) JOIN_ORDER(t3, t2@q1)*/ count(*) + FROM t1, t2, t3; + +--echo # Invalid mix of notations +EXPLAIN EXTENDED + SELECT /*+ QB_NAME(q1) JOIN_PREFIX(@q1 t2, t1@q1)*/ count(*) + FROM t1, t2, t3; + +--echo # Hint is correct +EXPLAIN EXTENDED + SELECT /*+ QB_NAME(qb1) JOIN_SUFFIX(t1@qb1, t2)*/ count(*) FROM t1, t2; + +EXPLAIN EXTENDED + SELECT /*+ QB_NAME(qb1) JOIN_PREFIX(@qb1, t2)*/ count(*) FROM t1, t2; + +--echo # Invalid table name +EXPLAIN EXTENDED + SELECT /*+ JOIN_SUFFIX(t3)*/ count(*) FROM t1, t2; + +--echo # Invalid query block name +EXPLAIN EXTENDED + SELECT /*+ QB_NAME(qb1) JOIN_SUFFIX(@qbXXX t1)*/ count(*) FROM t1, t2; + +EXPLAIN EXTENDED + SELECT /*+ QB_NAME(qb1) JOIN_SUFFIX(t1, t2@qb3)*/ count(*) FROM t1, t2; + +EXPLAIN EXTENDED + SELECT /*+ QB_NAME(qb1) JOIN_FIXED_ORDER(@qbXXX)*/ count(*) FROM t2, t1; + +--echo # Warning expected as the hint must not confuse `t2` in the subquery +--echo # with `t2` in the join +EXPLAIN EXTENDED + SELECT /*+ JOIN_PREFIX(t2@subq)*/ (SELECT /*+ QB_NAME(subq)*/ max(f1) FROM t2) as SQ, f1 + FROM t2; + +--echo # No more than 64 join order hints are allowed. It is hard to construct +--echo # a test case where 64 hints will be applicable and only one, exceeding +--echo # the maximum, will produce a warning. Usually so many hints will conflict +--echo # with each other and generate warnings. +--echo # But in the case below we can observe that the first warning +--echo # is about JOIN_ORDER(t1,t2,t3,t4,t5,t6) which is actually +--echo # the last hint in the list, and it is the 65th in order. +--echo # This happens because the check for exceeding the maximum is performed +--echo # during the preparation phase, while other checks are performed during +--echo # hints application. So, if JOIN_ORDER(t1,t2,t3,t4,t5,t6) +--echo # is mentioned first in the list of warnings, the test case passes. +EXPLAIN EXTENDED + SELECT /*+ + JOIN_PREFIX(t2,t1) JOIN_SUFFIX(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) + JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) + JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) + JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) + JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) + JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) + JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) + JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) + JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) + JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) + JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) + JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) + JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) + JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) + JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) + JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) + JOIN_ORDER(t1,t2,t3,t4,t5,t6) */ + count(*) FROM t1, t2, t3; + +--echo # Original query with no hints +let $query= SELECT count(*) FROM t1 JOIN t2 JOIN t3 + WHERE t1.f1 IN (SELECT f1 FROM t4) AND t2.f1 IN (SELECT f1 FROM t5); +eval $query; +eval explain extended $query; + +--echo # Check name resolving +let $query= SELECT /*+ QB_NAME(q1) JOIN_PREFIX(t3, t2, t2@subq2) */ count(*) FROM t1 JOIN t2 JOIN t3 + WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t2) AND + t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t2); +eval $query; +eval explain extended $query; + +--echo # Check conflicting hints +--echo # Second JOIN_PREFIX is conflicting +let $query= SELECT /*+ JOIN_PREFIX(t3, t2, t1) JOIN_PREFIX(t2, t1) */ count(*) FROM t1 JOIN t2 JOIN t3 + WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) + AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +eval $query; +eval explain extended $query; + +--echo # Second JOIN_SUFFIX is conflicting +let $query= SELECT /*+ JOIN_SUFFIX(t3, t2) JOIN_SUFFIX(t2, t1) */ count(*) FROM t1 JOIN t2 JOIN t3 + WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) + AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +eval $query; +eval explain extended $query; + +--echo # Both JOIN_ORDERs applicable +let $query= SELECT /*+ JOIN_ORDER(t3, t2) JOIN_ORDER(t1, t2, t5@subq2) */ count(*) + FROM t1 JOIN t2 JOIN t3 + WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) + AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +eval $query; +eval explain extended $query; + +--echo # Unresolved table name t7 in JOIN_ORDER hint, hint ignored +let $query= SELECT /*+ JOIN_ORDER(t1, t7, t5) */ count(*) FROM t1 JOIN t2 JOIN t3 + WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) + AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +eval $query; +eval explain extended $query; + +--echo # All hints are applicable +let $query= SELECT /*+ JOIN_PREFIX(t2, t5@subq2, t4@subq1) + JOIN_ORDER(t4@subq1, t3) JOIN_SUFFIX(t1) */ count(*) + FROM t1 JOIN t2 JOIN t3 + WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) + AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +eval $query; +eval explain extended $query; + +--echo # Second JOIN_ORDER is ignored +let $query= SELECT /*+ JOIN_ORDER(t3, t2) JOIN_ORDER(t2, t3) */ count(*) FROM t1 JOIN t2 JOIN t3 + WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) + AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +eval $query; +eval explain extended $query; + +--echo # JOIN_SUFFIX is ignored +let $query= SELECT /*+ JOIN_ORDER(t3, t2) JOIN_SUFFIX(t3) */ count(*) FROM t1 JOIN t2 JOIN t3 + WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) + AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +eval $query; +eval explain extended $query; + +--echo # JOIN_PREFIX is ignored +let $query= SELECT /*+ JOIN_ORDER(t3, t2) JOIN_PREFIX(t2) */ count(*) FROM t1 JOIN t2 JOIN t3 + WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) + AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +eval $query; +eval explain extended $query; + +--echo # All hints are applicable +let $query= SELECT /*+ JOIN_ORDER(t4@subq1, t3) JOIN_SUFFIX(t1) JOIN_PREFIX(t2, t5@subq2, t4@subq1) */ count(*) + FROM t1 JOIN t2 JOIN t3 + WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) + AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +eval $query; +eval explain extended $query; + +--echo # JOIN_PREFIX with all tables. +let $query= SELECT /*+ JOIN_PREFIX(t2, t5@subq2, t4@subq1, t3, t1) */ count(*) + FROM t1 JOIN t2 JOIN t3 + WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) + AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +eval $query; +eval explain extended $query; + +--echo # JOIN_SUFFIX with all tables. +let $query= SELECT /*+ JOIN_SUFFIX(t2, t5@subq2, t4@subq1, t3, t1) */ count(*) + FROM t1 JOIN t2 JOIN t3 + WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) + AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +eval $query; +eval explain extended $query; + +--echo # JOIN_ORDER with all tables. +let $query= SELECT /*+ JOIN_ORDER(t2, t5@subq2, t4@subq1, t3, t1) */ count(*) + FROM t1 JOIN t2 JOIN t3 + WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) + AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +eval $query; +eval explain extended $query; + +--echo # JOIN_PREFIX, JOIN_ORDER, JOIN_SUFFIX with all tables. +let $query= SELECT /*+ JOIN_SUFFIX(t2, t5@subq2, t4@subq1, t3, t1) + JOIN_ORDER(t2, t5@subq2, t4@subq1, t3, t1) + JOIN_PREFIX(t2, t5@subq2, t4@subq1, t3, t1) */ count(*) + FROM t1 JOIN t2 JOIN t3 + WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) + AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +eval $query; +eval explain extended $query; + +--echo # JOIN_ORDER is ignored due to STRAIGHT_JOIN. +let $query= SELECT /*+ QB_NAME(q1) JOIN_ORDER(t2, t1) */ STRAIGHT_JOIN count(*) + FROM t1 JOIN t2 JOIN t3 + WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) + AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +eval $query; +eval explain extended $query; + +--echo # Test JOIN_FIXED_ORDER. +let $query= SELECT /*+ QB_NAME(q1) JOIN_FIXED_ORDER(@q1) */ count(*) FROM t1 JOIN t2 JOIN t3 + WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) + AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +eval $query; +eval explain extended $query; + +let $query= SELECT /*+ JOIN_FIXED_ORDER() */ count(*) FROM t1 JOIN t2 JOIN t3 + WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) + AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +eval $query; +eval explain extended $query; + +let $query= SELECT /*+ QB_NAME(q1) */ count(*) FROM t1 JOIN t2 JOIN t3 + WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) + AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +eval $query; +eval explain extended $query; + +--echo # Testing STRAIGHT_JOIN + +let $query= SELECT count(*) FROM t1 JOIN t2 STRAIGHT_JOIN t3 + WHERE t1.f1 IN (SELECT f1 FROM t4) AND t2.f1 IN (SELECT f1 FROM t5); +eval $query; +eval explain extended $query; + +--echo # t3 can not be first +let $query= SELECT /*+ JOIN_PREFIX(t3, t1) */ count(*) FROM t1 JOIN t2 STRAIGHT_JOIN t3 + WHERE t1.f1 IN (SELECT f1 FROM t4) AND t2.f1 IN (SELECT f1 FROM t5); +eval $query; +eval explain extended $query; + +--echo # Hint is applicable +let $query= SELECT /*+ JOIN_PREFIX(t1, t2, t3) */ count(*) FROM t1 JOIN t2 STRAIGHT_JOIN t3 + WHERE t1.f1 IN (SELECT f1 FROM t4) AND t2.f1 IN (SELECT f1 FROM t5); +eval $query; +eval explain extended $query; + +--echo # Hint is applicable +let $query= SELECT /*+ JOIN_SUFFIX(t4, t5) */ count(*) FROM t1 JOIN t2 STRAIGHT_JOIN t3 + WHERE t1.f1 IN (SELECT f1 FROM t4) AND t2.f1 IN (SELECT f1 FROM t5); +eval $query; +eval explain extended $query; + +--echo # Alternative syntax +let $query= SELECT /*+ QB_NAME(q1) JOIN_ORDER(@q1 t2, t3, t1) */ count(*) + FROM t1 JOIN t2 JOIN t3 + WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) + AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +eval $query; +eval explain extended $query; + +--echo # Alternative syntax +let $query= SELECT /*+ QB_NAME(q1) JOIN_PREFIX(@q1 t2, t3, t1) */ count(*) + FROM t1 JOIN t2 JOIN t3 + WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) + AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +eval $query; +eval explain extended $query; + +--echo # Alternative syntax +let $query= SELECT /*+ QB_NAME(q1) JOIN_SUFFIX(@q1 t2, t3, t1) */ count(*) + FROM t1 JOIN t2 JOIN t3 + WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) + AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5); +eval $query; +eval explain extended $query; + + +DROP TABLE t1, t2, t3, t4 ,t5, t6; + +--echo # Testing embedded join + +CREATE TABLE t1 (f1 INT); +CREATE TABLE t2 (f1 INT); +CREATE TABLE t3 (f1 INT); +CREATE TABLE t4 (f1 INT); + +EXPLAIN EXTENDED SELECT /*+ JOIN_ORDER(t2, t4, t1) */ 1 FROM t1 + JOIN t2 ON 1 + RIGHT JOIN t3 ON 1 + JOIN t4 ON 1; + +EXPLAIN EXTENDED SELECT /*+ JOIN_ORDER(t2, t1, t4) */ 1 FROM t1 + JOIN t2 ON 1 + RIGHT JOIN t3 ON 1 + JOIN t4 ON 1; + +EXPLAIN EXTENDED SELECT /*+ JOIN_ORDER(t4, t1, t2) */ 1 FROM t1 + JOIN t2 ON 1 + RIGHT JOIN t3 ON 1 + JOIN t4 ON 1; + +EXPLAIN EXTENDED SELECT /*+ JOIN_ORDER(t3, t4) */ 1 FROM t1 + JOIN t2 ON 1 + RIGHT JOIN t3 ON 1 + JOIN t4 ON 1; + +EXPLAIN SELECT /*+ JOIN_ORDER(t4, t3) */ 1 FROM t1 + JOIN t2 ON 1 + RIGHT JOIN t3 ON 1 + JOIN t4 ON 1; + +EXPLAIN EXTENDED SELECT /*+ JOIN_SUFFIX(t1) */ 1 FROM t1 + JOIN t2 ON 1 + RIGHT JOIN t3 ON 1 + JOIN t4 ON 1; + +EXPLAIN EXTENDED SELECT /*+ JOIN_SUFFIX(t2, t1) */ 1 FROM t1 + JOIN t2 ON 1 + RIGHT JOIN t3 ON 1 + JOIN t4 ON 1; + +DROP TABLE t1, t2, t3, t4; + +CREATE TABLE t1 +( + f1 INT(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (f1) +); +INSERT INTO t1 VALUES (1),(2),(3); + +CREATE TABLE t2 +( + f1 INT(11) DEFAULT NULL +); +INSERT INTO t2 VALUES (0),(1),(2); + +CREATE TABLE t3 +( + f1 INT(11) DEFAULT NULL +); +INSERT INTO t3 VALUES (0),(1),(2); + +--echo # Original query +EXPLAIN EXTENDED DELETE +FROM ta1.* USING t1 AS ta1 JOIN t1 AS ta2 ON 1 + RIGHT OUTER JOIN t2 ON (ta1.f1 = t2.f1) +WHERE (9) IN (SELECT f1 FROM t3); + +--echo # Applicable hint +EXPLAIN EXTENDED DELETE /*+ JOIN_PREFIX(t2, t3, ta2) */ +FROM ta1.* USING t1 AS ta1 JOIN t1 AS ta2 ON 1 + RIGHT OUTER JOIN t2 ON (ta1.f1 = t2.f1) +WHERE (9) IN (SELECT f1 FROM t3); + +--echo # Applicable hint +EXPLAIN EXTENDED DELETE /*+ JOIN_PREFIX(t2, t3, ta1, ta2) */ +FROM ta1.* USING t1 AS ta1 JOIN t1 AS ta2 ON 1 + RIGHT OUTER JOIN t2 ON (ta1.f1 = t2.f1) +WHERE (9) IN (SELECT f1 FROM t3); + +--echo # Applicable hint +EXPLAIN EXTENDED DELETE /*+ JOIN_PREFIX(t2, t3, ta2, ta1) */ +FROM ta1.* USING t1 AS ta1 JOIN t1 AS ta2 ON 1 + RIGHT OUTER JOIN t2 ON (ta1.f1 = t2.f1) +WHERE (9) IN (SELECT f1 FROM t3); + +--echo # Hint should be ignored +EXPLAIN EXTENDED DELETE /*+ JOIN_SUFFIX(ta2, t3, ta1) */ +FROM ta1.* USING t1 AS ta1 JOIN t1 AS ta2 ON 1 + RIGHT OUTER JOIN t2 ON (ta1.f1 = t2.f1) +WHERE (9) IN (SELECT f1 FROM t3); + +--echo # Both hints are ignored +EXPLAIN EXTENDED DELETE /*+ JOIN_PREFIX(ta1, t2, t3) JOIN_SUFFIX(t3, ta2) */ +FROM ta1.* USING t1 AS ta1 JOIN t1 AS ta2 ON 1 + RIGHT OUTER JOIN t2 ON (ta1.f1 = t2.f1) +WHERE (9) IN (SELECT f1 FROM t3); + +DROP TABLE t1, t2, t3; + +--echo # Const table behavior, table order is not changed, hint is applicable. +--echo # Note: Const tables are excluded from the process of dependency setting +--echo # since they are always first in the table order. Note that it +--echo # does not prevent the hint from being applied to the non-const +--echo # tables of the hint. + +CREATE TABLE t1(f1 INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1); + +CREATE TABLE t2(f1 INT) ENGINE=InnoDB; +INSERT INTO t2 VALUES (1); + +EXPLAIN EXTENDED SELECT /*+ JOIN_PREFIX(t1, t2) */ 1 FROM t1 JOIN t2 ON t1.f1 = t2.f1; +EXPLAIN EXTENDED SELECT /*+ JOIN_PREFIX(t2, t1) */ 1 FROM t1 JOIN t2 ON t1.f1 = t2.f1; + +DROP TABLE t1, t2; + + +--echo # +--echo # Bug#23144274 WL9158:ASSERTION `JOIN->BEST_READ < DOUBLE(1.79769313486231570815E+308L)' FAILED +--echo # + +CREATE TABLE t1 ( +f1 int(11) NOT NULL AUTO_INCREMENT, +f2 varchar(255) DEFAULT NULL, +PRIMARY KEY (f1)); + +CREATE TABLE t2 ( +f1 int(11) NOT NULL AUTO_INCREMENT, +f2 varchar(255) CHARACTER SET utf8mb3 DEFAULT NULL, +f3 varchar(10) DEFAULT NULL, +PRIMARY KEY (f1), +KEY f3(f3)); + +EXPLAIN SELECT /*+ JOIN_SUFFIX(t1, t2) */ t2.f3 FROM t2 LEFT JOIN t1 + ON t2.f1 = t1.f1 WHERE t1.f2 NOT LIKE ('FMGAU') OR t2.f2 > 't'; + +DROP TABLE t1, t2; + + +CREATE TABLE t1 +( + f1 int(11) DEFAULT NULL, + KEY f1 (f1) +); + +CREATE TABLE t2 +( + f1 int(11) DEFAULT NULL, + f2 varchar(255) CHARACTER SET utf8mb3 DEFAULT NULL, + KEY f2 (f2), + KEY f1 (f1) +); + +CREATE TABLE t3 ( + f1 int(11) DEFAULT NULL, + f2 varchar(255) CHARACTER SET cp932 DEFAULT NULL, + KEY f1 (f1), + KEY f2 (f2) +); + +EXPLAIN EXTENDED SELECT /*+ JOIN_ORDER(t2, t3) JOIN_ORDER(t1, t2) */ t3.f1 + FROM ( t2 INNER JOIN t3 ON t3.f2 = t2.f2 LEFT JOIN t1 ON t1.f1 = t3.f1 ) + WHERE NOT (t2.f1 >= 7); + +EXPLAIN EXTENDED SELECT /*+ JOIN_ORDER(t1, t2) JOIN_ORDER(t2, t3) */ t3.f1 + FROM ( t2 INNER JOIN t3 ON t3.f2 = t2.f2 LEFT JOIN t1 ON t1.f1 = t3.f1 ) + WHERE NOT (t2.f1 >= 7); + +DROP TABLE t1, t2, t3; + +CREATE TABLE t1 ( + f1 INT(11) NOT NULL AUTO_INCREMENT, + f2 INT(11) DEFAULT NULL, + PRIMARY KEY (f1) +); + +CREATE TABLE t2 ( + f1 INT(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (f1) +); + +EXPLAIN EXTENDED SELECT /*+ JOIN_PREFIX(t1, t1) */ t2.f1 FROM t1 JOIN t2 ON t1.f2 = t2.f1; + +DROP TABLE t1, t2; + +CREATE TABLE t1 +( + f1 DATETIME, + f2 DATE, + f3 VARCHAR(1), + KEY (f1) +) ENGINE=myisam; + +CREATE TABLE t2 +( + f1 VARCHAR(1), + f2 INT, + f3 VARCHAR(1), + KEY (f1) +) ENGINE=innodb; + +CREATE TABLE t3 +( + f1 VARCHAR(1), + f2 DATE, + f3 DATETIME, + f4 INT +) ENGINE=myisam; + +# Warning "Field or reference 'test.als2.f2' of SELECT #2 was resolved in SELECT #1" +# is generated during both PREPARE and EXECUTE of a prepared statement, so disable +# the PS protocol for this test +--disable_ps_protocol +EXPLAIN EXTENDED +UPDATE /*+ JOIN_ORDER(t2, als1, als3) JOIN_FIXED_ORDER() */ t3 AS als1 + JOIN t1 AS als2 ON (als1.f3 = als2 .f1) + JOIN t1 AS als3 ON (als1.f1 = als3.f3) + RIGHT OUTER JOIN t3 AS als4 ON (als1.f3 = als4.f2) +SET als1.f4 = 'eogqjvbhzodzimqahyzlktkbexkhdwxwgifikhcgblhgswxyutepc' +WHERE ('i','b') IN (SELECT f3, f1 FROM t2 WHERE f2 <> f2 AND als2.f2 IS NULL); +--enable_ps_protocol + +DROP TABLE t1, t2, t3; + + +CREATE TABLE t1( +f1 VARCHAR(1)) ENGINE=myisam; + +CREATE TABLE t2( +f1 VARCHAR(1), +f2 VARCHAR(1), +f3 DATETIME, +KEY(f2)) ENGINE=innodb; + +CREATE TABLE t3( +f1 INT, +f2 DATE, +f3 VARCHAR(1), +KEY(f3)) ENGINE=myisam; + +CREATE TABLE t4( +f1 VARCHAR(1), +KEY(f1)) ENGINE=innodb; +ALTER TABLE t4 DISABLE KEYS; +INSERT INTO t4 VALUES ('x'), (NULL), ('d'), ('x'), ('u'); +ALTER TABLE t4 ENABLE KEYS; + +CREATE TABLE t5( +f1 VARCHAR(1), +KEY(f1) ) ENGINE=myisam; +INSERT INTO t5 VALUES (NULL), ('s'), ('c'), ('x'), ('z'); + +EXPLAIN EXTENDED UPDATE /*+ JOIN_ORDER(t4, alias1, alias3) */ t3 AS alias1 + JOIN t5 ON (alias1.f3 = t5.f1) + JOIN t3 AS alias3 ON (alias1.f2 = alias3.f2 ) + RIGHT OUTER JOIN t1 ON (alias1.f3 = t1.f1) +SET alias1.f1 = -1 +WHERE ( 'v', 'o' ) IN +(SELECT DISTINCT t2.f1, t2.f2 FROM t4 RIGHT OUTER JOIN t2 ON (t4.f1 = t2.f1) + WHERE t2.f3 BETWEEN '2001-10-04' AND '2003-05-15'); + +DROP TABLE t1, t2, t3, t4, t5; + +CREATE TABLE t1 ( + f1 INT(11) DEFAULT NULL, + f3 VARCHAR(1) DEFAULT NULL, + f2 INT(11) DEFAULT NULL, + KEY (f1) +) ENGINE=MyISAM; + +CREATE TABLE t2( + f1 INT(11) DEFAULT NULL +) ENGINE=MyISAM; + +CREATE TABLE t3 ( + f1 VARCHAR(1) DEFAULT NULL, + f2 VARCHAR(1) DEFAULT NULL, + KEY (f2) +) ENGINE=InnoDB; + + +# Warning "Field or reference 'test.ta2.f3' of SELECT #2 was resolved in SELECT #1" +# is generated during both PREPARE and EXECUTE of a prepared statement, so disable +# the PS protocol for this test +--disable_ps_protocol +EXPLAIN EXTENDED UPDATE /*+ JOIN_SUFFIX(ta1, t2) */ + t1 AS ta1 JOIN t1 AS ta2 ON ta1.f1 = ta2.f1 RIGHT JOIN t2 ON (ta1.f1 = t2.f1) +SET ta1.f2 = '', ta2.f3 = '' +WHERE ('n', 'r') IN (SELECT f2, f1 FROM t3 WHERE f1 <> f2 XOR ta2.f3 IS NULL); +--enable_ps_protocol + +DROP TABLE t1, t2, t3; + + +CREATE TABLE t2(f1 VARCHAR(255) DEFAULT NULL, f2 INT(11) DEFAULT NULL, + KEY (f1), KEY (f2)) charset latin1 ENGINE=MyISAM; + +CREATE TABLE t4(f1 INT(11) DEFAULT NULL, f2 INT(11) DEFAULT NULL, KEY (f1)) +charset latin1 ENGINE=MyISAM; +CREATE TABLE t5(f1 INT(11) NOT NULL AUTO_INCREMENT, f2 INT(11) DEFAULT NULL, PRIMARY KEY (f1)) +charset latin1 ENGINE=InnoDB; +CREATE TABLE t6(f1 INT(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (f1)) +charset latin1 ENGINE=InnoDB; +CREATE TABLE t7 (f1 VARCHAR(255) DEFAULT NULL) +charset latin1 ENGINE=InnoDB; + +CREATE TABLE t10(f1 INT(11) NOT NULL AUTO_INCREMENT,f2 INT(11) DEFAULT NULL,f3 VARCHAR(10) DEFAULT NULL, + PRIMARY KEY (f1),KEY (f2),KEY (f3)) charset latin1 ENGINE=MyISAM; + +CREATE TABLE t11(f1 INT(11) DEFAULT NULL,f2 VARCHAR(10) DEFAULT NULL, + KEY (f1),KEY (f2)) charset latin1 ENGINE=InnoDB; + +EXPLAIN EXTENDED +SELECT /*+ JOIN_ORDER(alias11, alias8) */ 1 +FROM t4 AS alias4 + LEFT JOIN t5 AS alias5 JOIN t6 AS alias6 ON alias5.f2 = alias6.f1 + LEFT JOIN t7 AS alias7 JOIN t2 AS alias8 ON alias7.f1 = alias8.f1 + ON alias5.f1 = alias8.f2 ON alias4.f2 = alias6.f1 + JOIN t10 AS alias10 JOIN t11 AS alias11 ON alias10.f1 = alias11.f1 + ON alias4.f2 = alias11.f2; + +EXPLAIN EXTENDED +SELECT /*+ JOIN_ORDER(alias11, alias10, alias8, alias7) */ 1 +FROM t4 AS alias4 + LEFT JOIN t5 AS alias5 JOIN t6 AS alias6 ON alias5.f2 = alias6.f1 + LEFT JOIN t7 AS alias7 JOIN t2 AS alias8 ON alias7.f1 = alias8.f1 + ON alias5.f1 = alias8.f2 ON alias4.f2 = alias6.f1 + JOIN t10 AS alias10 JOIN t11 AS alias11 ON alias10.f1 = alias11.f1 + ON alias4.f2 = alias11.f2; + +DROP TABLES t2, t4, t5, t6, t7, t10, t11; + +CREATE TABLE t1 (f1 VARCHAR(255) DEFAULT NULL, f2 VARCHAR(255) DEFAULT NULL, + KEY (f1), KEY (f2)) ENGINE=InnoDB; + +CREATE TABLE t2(f1 VARCHAR(255) DEFAULT NULL, f2 INT(11) DEFAULT NULL, + KEY (f1), KEY (f2)) ENGINE=InnoDB; + +CREATE TABLE t3( + f1 INT(11) NOT NULL AUTO_INCREMENT, f2 VARCHAR(255) DEFAULT NULL, + PRIMARY KEY (f1), KEY (f2)) ENGINE=InnoDB; + +CREATE TABLE t4(f1 INT(11) DEFAULT NULL, f2 INT(11) DEFAULT NULL, KEY (f1)) ENGINE=InnoDB; +CREATE TABLE t6(f1 INT(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (f1)) ENGINE=InnoDB; +CREATE TABLE t7 (f1 VARCHAR(255) DEFAULT NULL) ENGINE=InnoDB; + +CREATE TABLE t10(f1 INT(11) NOT NULL AUTO_INCREMENT,f2 INT(11) DEFAULT NULL,f3 VARCHAR(10) DEFAULT NULL, + PRIMARY KEY (f1),KEY (f2),KEY (f3)) ENGINE=InnoDB; + +EXPLAIN EXTENDED SELECT /*+ JOIN_ORDER(alias8, alias6) */ 1 +FROM t1 AS alias1 + LEFT JOIN t7 alias7 + JOIN t2 AS alias2 + LEFT JOIN t3 AS alias3 JOIN t4 AS alias4 ON alias4.f2 = alias3.f1 + ON alias4.f1 = alias2.f1 + ON alias2.f2 = alias7.f1 + JOIN t10 AS alias5 + LEFT JOIN t6 AS alias6 JOIN t2 AS alias8 ON alias6.f1 = alias8.f2 + ON alias6.f1 = alias5.f1 + ON alias5.f3 = alias7.f1 + ON alias1.f2 = alias7.f1; + +DROP TABLES t1, t2, t3, t4, t6, t7, t10; + + +--echo # +--echo # Bug#23144230 WL#9158 : OPT_HINTS_QB::APPLY_JOIN_ORDER_HINTS - MYSQLD GOT SIGNAL 11 +--echo # + +CREATE TABLE t1 ( +f1 int(11) NOT NULL AUTO_INCREMENT, +f2 int(11) DEFAULT NULL, +f3 int(11) DEFAULT NULL, +PRIMARY KEY (f1), +KEY f2 (f2)) +ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1; + +CREATE TABLE t2 ( +f1 int(11) NOT NULL AUTO_INCREMENT, +f2 int(11) DEFAULT NULL, +f3 int(11) DEFAULT NULL, +PRIMARY KEY (f1), +KEY f2 (f2)) +ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1; + +EXPLAIN EXTENDED SELECT /*+ JOIN_PREFIX(alias1) */ alias2.f3 AS field1 + FROM ( SELECT * FROM t1 ) AS alias1 JOIN ( SELECT * FROM t2 ) AS alias2 + ON alias1.f2 = alias2.f3 +WHERE alias2.f2 IS NULL HAVING (field1 != 3 AND field1 >= 8); + +DROP TABLE t1, t2; + + +--echo # +--echo # Bug#23651098 WL#9158 : ASSERTION `!(SJ_NEST->SJ_INNER_TABLES & JOIN->CONST_TABLE_MAP)' FAILED +--echo # + +CREATE TABLE t1 +( + f1 INT(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (f1) +) ENGINE=InnoDB; + +CREATE TABLE t2 +( + f1 VARCHAR(1) DEFAULT NULL +) ENGINE=MyISAM; + +CREATE TABLE t3 +( + f1 VARCHAR(1) DEFAULT NULL +) ENGINE=MyISAM; + +EXPLAIN EXTENDED SELECT /*+ JOIN_PREFIX(t2, t1) */ t1.f1 FROM t1, t2 +WHERE t2.f1 IN (SELECT t3.f1 FROM t3) AND t1.f1 = 183; + +DROP TABLE t1, t2, t3; + +--echo # +--echo # Bug23715779 SELECT QUERY WITH JOIN_PREFIX() HINT RETURNS INCORRECT RESULT +--echo # + +CREATE TABLE t1(f1 INT(11) NOT NULL); +INSERT INTO t1 VALUES (10); + +CREATE TABLE t2 +( + f1 INT(11) NOT NULL AUTO_INCREMENT, + f2 INT(11) DEFAULT NULL, + PRIMARY KEY (f1), + KEY (f2) +); +INSERT INTO t2 VALUES (1, 7), (2, 1), (4, 7); + +CREATE TABLE t4(f1 INT DEFAULT NULL); +INSERT INTO t4 VALUES (2); + +ANALYZE TABLE t1, t2, t4; + +let $query= +SELECT +COUNT(*) FROM t1 JOIN t2 AS ta3 JOIN t2 AS ta4 +WHERE ta4.f1 IN (SELECT /*+ QB_NAME(qb1) */ f1 FROM t4) AND + ta3.f2 IN (SELECT /*+ QB_NAME(qb2) */ f2 FROM t2); +eval $query; +eval explain extended $query; + +let $query= +SELECT /*+ JOIN_PREFIX(t2@qb2, t4@qb1, ta3, ta4) */ +COUNT(*) FROM t1 JOIN t2 AS ta3 JOIN t2 AS ta4 +WHERE ta4.f1 IN (SELECT /*+ QB_NAME(qb1) */ f1 FROM t4) AND + ta3.f2 IN (SELECT /*+ QB_NAME(qb2) */ f2 FROM t2); +eval $query; +eval explain extended $query; + +DROP TABLE t1, t2, t4; diff --git a/mysql-test/main/opt_hints_subquery.result b/mysql-test/main/opt_hints_subquery.result index ff8ed5afbeb..d37f7cc77ca 100644 --- a/mysql-test/main/opt_hints_subquery.result +++ b/mysql-test/main/opt_hints_subquery.result @@ -158,7 +158,7 @@ a 3 4 Warnings: -Warning 4208 Query block name `qb1` is not found for SUBQUERY hint +Warning 4211 Query block name `qb1` is not found for SUBQUERY hint SELECT /*+ SUBQUERY() */ a FROM t1; a 1 @@ -195,15 +195,15 @@ SELECT /*+ SEMIJOIN() SEMIJOIN(dupsweedout) NO_SEMIJOIN(firstmatch)*/ a FROM t1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index Warnings: -Warning 4207 Hint SEMIJOIN(DUPSWEEDOUT) is ignored as conflicting/duplicated -Warning 4207 Hint NO_SEMIJOIN(FIRSTMATCH) is ignored as conflicting/duplicated +Warning 4210 Hint SEMIJOIN(DUPSWEEDOUT) is ignored as conflicting/duplicated +Warning 4210 Hint NO_SEMIJOIN(FIRSTMATCH) is ignored as conflicting/duplicated Note 1003 select /*+ SEMIJOIN(@`select#1`) */ `test`.`t1`.`a` AS `a` from `test`.`t1` EXPLAIN EXTENDED SELECT /*+ SEMIJOIN(loosescan,materialization) SEMIJOIN(dupsweedout)*/ a FROM t1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index Warnings: -Warning 4207 Hint SEMIJOIN(DUPSWEEDOUT) is ignored as conflicting/duplicated +Warning 4210 Hint SEMIJOIN(DUPSWEEDOUT) is ignored as conflicting/duplicated Note 1003 select /*+ SEMIJOIN(@`select#1` LOOSESCAN, MATERIALIZATION) */ `test`.`t1`.`a` AS `a` from `test`.`t1` EXPLAIN EXTENDED SELECT /*+ NO_SEMIJOIN(firstmatch,loosescan,materialization) SEMIJOIN() NO_SEMIJOIN()*/ a @@ -211,8 +211,8 @@ FROM t1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index Warnings: -Warning 4207 Hint SEMIJOIN() is ignored as conflicting/duplicated -Warning 4207 Hint NO_SEMIJOIN() is ignored as conflicting/duplicated +Warning 4210 Hint SEMIJOIN() is ignored as conflicting/duplicated +Warning 4210 Hint NO_SEMIJOIN() is ignored as conflicting/duplicated Note 1003 select /*+ NO_SEMIJOIN(@`select#1` FIRSTMATCH, LOOSESCAN, MATERIALIZATION) */ `test`.`t1`.`a` AS `a` from `test`.`t1` EXPLAIN EXTENDED SELECT /*+ QB_NAME(qb1) SEMIJOIN(@qb1) SEMIJOIN(loosescan) NO_SEMIJOIN(@qb1 dupsweedout)*/ a @@ -220,36 +220,36 @@ FROM t1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index Warnings: -Warning 4207 Hint SEMIJOIN(LOOSESCAN) is ignored as conflicting/duplicated -Warning 4207 Hint NO_SEMIJOIN(@`qb1` DUPSWEEDOUT) is ignored as conflicting/duplicated +Warning 4210 Hint SEMIJOIN(LOOSESCAN) is ignored as conflicting/duplicated +Warning 4210 Hint NO_SEMIJOIN(@`qb1` DUPSWEEDOUT) is ignored as conflicting/duplicated Note 1003 select /*+ QB_NAME(`qb1`) SEMIJOIN(@`qb1`) */ `test`.`t1`.`a` AS `a` from `test`.`t1` EXPLAIN EXTENDED SELECT /*+ SEMIJOIN(firstmatch) NO_SEMIJOIN()*/ a FROM t1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index Warnings: -Warning 4207 Hint NO_SEMIJOIN() is ignored as conflicting/duplicated +Warning 4210 Hint NO_SEMIJOIN() is ignored as conflicting/duplicated Note 1003 select /*+ SEMIJOIN(@`select#1` FIRSTMATCH) */ `test`.`t1`.`a` AS `a` from `test`.`t1` EXPLAIN EXTENDED SELECT /*+ SUBQUERY(materialization) SUBQUERY(intoexists)*/ a FROM t1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index Warnings: -Warning 4207 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated +Warning 4210 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated Note 1003 select /*+ SUBQUERY(@`select#1` MATERIALIZATION) */ `test`.`t1`.`a` AS `a` from `test`.`t1` EXPLAIN EXTENDED SELECT /*+ SEMIJOIN() SUBQUERY(materialization) SUBQUERY(intoexists)*/ a FROM t1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index Warnings: -Warning 4207 Hint SUBQUERY(MATERIALIZATION) is ignored as conflicting/duplicated -Warning 4207 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated +Warning 4210 Hint SUBQUERY(MATERIALIZATION) is ignored as conflicting/duplicated +Warning 4210 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated Note 1003 select /*+ SEMIJOIN(@`select#1`) */ `test`.`t1`.`a` AS `a` from `test`.`t1` EXPLAIN EXTENDED SELECT /*+ SUBQUERY(materialization) SUBQUERY(intoexists)*/ a FROM t1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index Warnings: -Warning 4207 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated +Warning 4210 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated Note 1003 select /*+ SUBQUERY(@`select#1` MATERIALIZATION) */ `test`.`t1`.`a` AS `a` from `test`.`t1` EXPLAIN EXTENDED SELECT /*+ SUBQUERY(materialization) SUBQUERY(intoexists) SUBQUERY(materialization)*/ a @@ -257,32 +257,32 @@ FROM t1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index Warnings: -Warning 4207 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated -Warning 4207 Hint SUBQUERY(MATERIALIZATION) is ignored as conflicting/duplicated +Warning 4210 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated +Warning 4210 Hint SUBQUERY(MATERIALIZATION) is ignored as conflicting/duplicated Note 1003 select /*+ SUBQUERY(@`select#1` MATERIALIZATION) */ `test`.`t1`.`a` AS `a` from `test`.`t1` EXPLAIN EXTENDED SELECT /*+ SUBQUERY(materialization) SEMIJOIN(firstmatch) SUBQUERY(intoexists)*/ a FROM t1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index Warnings: -Warning 4207 Hint SEMIJOIN(FIRSTMATCH) is ignored as conflicting/duplicated -Warning 4207 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated +Warning 4210 Hint SEMIJOIN(FIRSTMATCH) is ignored as conflicting/duplicated +Warning 4210 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated Note 1003 select /*+ SUBQUERY(@`select#1` MATERIALIZATION) */ `test`.`t1`.`a` AS `a` from `test`.`t1` EXPLAIN EXTENDED SELECT /*+ QB_NAME(qb1) SEMIJOIN(@qb1) SUBQUERY(@qb1 materialization) SUBQUERY(intoexists)*/ a FROM t1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index Warnings: -Warning 4207 Hint SUBQUERY(@`qb1` MATERIALIZATION) is ignored as conflicting/duplicated -Warning 4207 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated +Warning 4210 Hint SUBQUERY(@`qb1` MATERIALIZATION) is ignored as conflicting/duplicated +Warning 4210 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated Note 1003 select /*+ QB_NAME(`qb1`) SEMIJOIN(@`qb1`) */ `test`.`t1`.`a` AS `a` from `test`.`t1` EXPLAIN EXTENDED SELECT /*+ QB_NAME(qb1) SUBQUERY(@qb1 materialization) SEMIJOIN(@qb1 firstmatch) SUBQUERY(intoexists)*/ a FROM t1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index Warnings: -Warning 4207 Hint SEMIJOIN(@`qb1` FIRSTMATCH) is ignored as conflicting/duplicated -Warning 4207 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated +Warning 4210 Hint SEMIJOIN(@`qb1` FIRSTMATCH) is ignored as conflicting/duplicated +Warning 4210 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated Note 1003 select /*+ QB_NAME(`qb1`) SUBQUERY(@`qb1` MATERIALIZATION) */ `test`.`t1`.`a` AS `a` from `test`.`t1` EXPLAIN EXTENDED SELECT /*+ SEMIJOIN(@qb1) SEMIJOIN(loosescan) NO_SEMIJOIN(@qb1 dupsweedout)*/ a @@ -291,7 +291,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY ALL NULL NULL NULL NULL 4 100.00 2 DERIVED t2 index NULL a 4 NULL 4 100.00 Using index Warnings: -Warning 4207 Hint NO_SEMIJOIN(@`qb1` DUPSWEEDOUT) is ignored as conflicting/duplicated +Warning 4210 Hint NO_SEMIJOIN(@`qb1` DUPSWEEDOUT) is ignored as conflicting/duplicated Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`qb1`) SEMIJOIN(@`select#1` LOOSESCAN) */ `tt`.`a` AS `a` from (/* select#2 */ select /*+ QB_NAME(`qb1`) */ `test`.`t2`.`a` AS `a` from `test`.`t2`) `tt` DROP TABLE t1, t2 ,t3; set optimizer_switch=default; @@ -1434,7 +1434,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index 2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index Warnings: -Warning 4207 Hint SEMIJOIN() is ignored as conflicting/duplicated +Warning 4210 Hint SEMIJOIN() is ignored as conflicting/duplicated Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`select#2`) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,(((`test`.`t2`.`a`) in t1 on PRIMARY)))) # Try opposite order EXPLAIN EXTENDED @@ -1444,7 +1444,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 index PRIMARY PRIMARY 4 NULL 4 100.00 Using index 1 PRIMARY t2 ref a a 4 test.t1.a 1 100.00 Using index Warnings: -Warning 4207 Hint NO_SEMIJOIN() is ignored as conflicting/duplicated +Warning 4210 Hint NO_SEMIJOIN() is ignored as conflicting/duplicated Note 1003 select /*+ SEMIJOIN(@`select#2`) */ `test`.`t2`.`a` AS `a` from `test`.`t1` join `test`.`t2` where `test`.`t2`.`a` = `test`.`t1`.`a` # Specify at different levels, hint inside block has effect EXPLAIN EXTENDED @@ -1454,7 +1454,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 index PRIMARY PRIMARY 4 NULL 4 100.00 Using index 1 PRIMARY t2 ref a a 4 test.t1.a 1 100.00 Using index Warnings: -Warning 4207 Hint NO_SEMIJOIN(@`subq` ) is ignored as conflicting/duplicated +Warning 4210 Hint NO_SEMIJOIN(@`subq` ) is ignored as conflicting/duplicated Note 1003 select /*+ SEMIJOIN(@`subq`) */ `test`.`t2`.`a` AS `a` from `test`.`t1` join `test`.`t2` where `test`.`t2`.`a` = `test`.`t1`.`a` # Specify at different levels, opposite order EXPLAIN EXTENDED @@ -1464,7 +1464,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index 2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index Warnings: -Warning 4207 Hint SEMIJOIN(@`subq` ) is ignored as conflicting/duplicated +Warning 4210 Hint SEMIJOIN(@`subq` ) is ignored as conflicting/duplicated Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq`) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,(((`test`.`t2`.`a`) in t1 on PRIMARY)))) # Duplicate hints also gives warning, but hint has effect EXPLAIN EXTENDED @@ -1474,7 +1474,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 index PRIMARY PRIMARY 4 NULL 4 100.00 Using index 1 PRIMARY t2 ref a a 4 test.t1.a 1 100.00 Using index Warnings: -Warning 4207 Hint SEMIJOIN(@`subq` ) is ignored as conflicting/duplicated +Warning 4210 Hint SEMIJOIN(@`subq` ) is ignored as conflicting/duplicated Note 1003 select /*+ SEMIJOIN(@`subq`) */ `test`.`t2`.`a` AS `a` from `test`.`t1` join `test`.`t2` where `test`.`t2`.`a` = `test`.`t1`.`a` EXPLAIN EXTENDED SELECT /*+ NO_SEMIJOIN(@subq) */ * FROM t2 @@ -1483,7 +1483,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index 2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index Warnings: -Warning 4207 Hint NO_SEMIJOIN(@`subq` ) is ignored as conflicting/duplicated +Warning 4210 Hint NO_SEMIJOIN(@`subq` ) is ignored as conflicting/duplicated Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq`) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,(((`test`.`t2`.`a`) in t1 on PRIMARY)))) # Multiple subqueries with conflicting hints EXPLAIN EXTENDED @@ -1495,8 +1495,8 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; Start temporary; End temporary 2 DEPENDENT SUBQUERY t3 index_subquery a a 4 func 1 100.00 Using index Warnings: -Warning 4207 Hint SEMIJOIN(@`subq1` LOOSESCAN) is ignored as conflicting/duplicated -Warning 4207 Hint SEMIJOIN(@`subq2` FIRSTMATCH) is ignored as conflicting/duplicated +Warning 4210 Hint SEMIJOIN(@`subq1` LOOSESCAN) is ignored as conflicting/duplicated +Warning 4210 Hint SEMIJOIN(@`subq2` FIRSTMATCH) is ignored as conflicting/duplicated Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq1`) SEMIJOIN(@`subq2` LOOSESCAN) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t2`) where `test`.`t2`.`a` = `test`.`t1`.`b` and <`test`.`t1`.`a`>((`test`.`t1`.`a`,(((`test`.`t1`.`a`) in t3 on a)))) EXPLAIN EXTENDED SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN) SEMIJOIN(@subq2 FIRSTMATCH) */ * FROM t1 @@ -1507,8 +1507,8 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ref a a 4 test.t1.a 1 100.00 Using index; FirstMatch(t1) 1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; Start temporary; End temporary Warnings: -Warning 4207 Hint SEMIJOIN(@`subq1` LOOSESCAN) is ignored as conflicting/duplicated -Warning 4207 Hint SEMIJOIN(@`subq2` FIRSTMATCH) is ignored as conflicting/duplicated +Warning 4210 Hint SEMIJOIN(@`subq1` LOOSESCAN) is ignored as conflicting/duplicated +Warning 4210 Hint SEMIJOIN(@`subq2` FIRSTMATCH) is ignored as conflicting/duplicated Note 1003 select /*+ NO_SEMIJOIN(@`subq1` LOOSESCAN) SEMIJOIN(@`subq2` LOOSESCAN) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t3`.`a` = `test`.`t1`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b` # Conflicting hints in same hint comment EXPLAIN EXTENDED @@ -1520,7 +1520,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.a 1 25.00 Using where 1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; FirstMatch(t1) Warnings: -Warning 4207 Hint SEMIJOIN(@`subq1` FIRSTMATCH) is ignored as conflicting/duplicated +Warning 4210 Hint SEMIJOIN(@`subq1` FIRSTMATCH) is ignored as conflicting/duplicated Note 1003 select /*+ SEMIJOIN(@`subq1` LOOSESCAN) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t1`.`a` = `test`.`t3`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b` EXPLAIN EXTENDED SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN) NO_SEMIJOIN(@subq1 LOOSESCAN) */ * @@ -1532,7 +1532,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.a 1 25.00 Using where 1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; FirstMatch(t1) Warnings: -Warning 4207 Hint NO_SEMIJOIN(@`subq1` LOOSESCAN) is ignored as conflicting/duplicated +Warning 4210 Hint NO_SEMIJOIN(@`subq1` LOOSESCAN) is ignored as conflicting/duplicated Note 1003 select /*+ SEMIJOIN(@`subq1` LOOSESCAN) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t1`.`a` = `test`.`t3`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b` EXPLAIN EXTENDED SELECT /*+ NO_SEMIJOIN(@subq1 LOOSESCAN) NO_SEMIJOIN(@subq1 FIRSTMATCH) */ * @@ -1544,7 +1544,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ref a a 4 test.t1.a 1 100.00 Using index; FirstMatch(t1) 1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; FirstMatch(t3) Warnings: -Warning 4207 Hint NO_SEMIJOIN(@`subq1` FIRSTMATCH) is ignored as conflicting/duplicated +Warning 4210 Hint NO_SEMIJOIN(@`subq1` FIRSTMATCH) is ignored as conflicting/duplicated Note 1003 select /*+ NO_SEMIJOIN(@`subq1` LOOSESCAN) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t3`.`a` = `test`.`t1`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b` # Non-supported strategies should give warnings EXPLAIN EXTENDED @@ -1770,7 +1770,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index 2 MATERIALIZED t1 index NULL PRIMARY 4 NULL 4 100.00 Using index Warnings: -Warning 4207 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated +Warning 4210 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated Note 1003 /* select#1 */ select /*+ SUBQUERY(@`select#2` MATERIALIZATION) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,`test`.`t2`.`a` in ( (/* select#2 */ select `test`.`t1`.`a` from `test`.`t1` ), (`test`.`t2`.`a` in on distinct_key where `test`.`t2`.`a` = ``.`a`)))) # Try opposite order EXPLAIN EXTENDED @@ -1781,7 +1781,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index 2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index Warnings: -Warning 4207 Hint SUBQUERY(MATERIALIZATION) is ignored as conflicting/duplicated +Warning 4210 Hint SUBQUERY(MATERIALIZATION) is ignored as conflicting/duplicated Note 1003 /* select#1 */ select /*+ SUBQUERY(@`select#2` INTOEXISTS) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,(((`test`.`t2`.`a`) in t1 on PRIMARY)))) # Specify at different levels, hint inside block has effect EXPLAIN EXTENDED @@ -1791,7 +1791,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index 2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index Warnings: -Warning 4207 Hint SUBQUERY(@`subq` MATERIALIZATION) is ignored as conflicting/duplicated +Warning 4210 Hint SUBQUERY(@`subq` MATERIALIZATION) is ignored as conflicting/duplicated Note 1003 /* select#1 */ select /*+ SUBQUERY(@`subq` INTOEXISTS) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,(((`test`.`t2`.`a`) in t1 on PRIMARY)))) # Specify at different levels, opposite order EXPLAIN EXTENDED @@ -1801,7 +1801,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index 2 MATERIALIZED t1 index NULL PRIMARY 4 NULL 4 100.00 Using index Warnings: -Warning 4207 Hint SUBQUERY(@`subq` INTOEXISTS) is ignored as conflicting/duplicated +Warning 4210 Hint SUBQUERY(@`subq` INTOEXISTS) is ignored as conflicting/duplicated Note 1003 /* select#1 */ select /*+ SUBQUERY(@`subq` MATERIALIZATION) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,`test`.`t2`.`a` in ( (/* select#2 */ select /*+ QB_NAME(`subq`) */ `test`.`t1`.`a` from `test`.`t1` ), (`test`.`t2`.`a` in on distinct_key where `test`.`t2`.`a` = ``.`a`)))) # Specifying combinations of SUBQUERY and SEMIJOIN/NO_SEMIJOIN # for same query block gives warning @@ -1813,7 +1813,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index 2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index Warnings: -Warning 4207 Hint SEMIJOIN() is ignored as conflicting/duplicated +Warning 4210 Hint SEMIJOIN() is ignored as conflicting/duplicated Note 1003 /* select#1 */ select /*+ SUBQUERY(@`select#2` INTOEXISTS) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,(((`test`.`t2`.`a`) in t1 on PRIMARY)))) # Try opposite order EXPLAIN EXTENDED @@ -1823,7 +1823,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index 2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index Warnings: -Warning 4207 Hint SUBQUERY(MATERIALIZATION) is ignored as conflicting/duplicated +Warning 4210 Hint SUBQUERY(MATERIALIZATION) is ignored as conflicting/duplicated Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`select#2`) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,(((`test`.`t2`.`a`) in t1 on PRIMARY)))) # Specify at different levels, hint inside block has effect EXPLAIN EXTENDED @@ -1833,7 +1833,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 index PRIMARY PRIMARY 4 NULL 4 100.00 Using index 1 PRIMARY t2 ref a a 4 test.t1.a 1 100.00 Using index Warnings: -Warning 4207 Hint SUBQUERY(@`subq` MATERIALIZATION) is ignored as conflicting/duplicated +Warning 4210 Hint SUBQUERY(@`subq` MATERIALIZATION) is ignored as conflicting/duplicated Note 1003 select /*+ SEMIJOIN(@`subq`) */ `test`.`t2`.`a` AS `a` from `test`.`t1` join `test`.`t2` where `test`.`t2`.`a` = `test`.`t1`.`a` EXPLAIN EXTENDED SELECT /*+ SUBQUERY(@subq INTOEXISTS) */ * FROM t2 @@ -1842,7 +1842,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index 2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index Warnings: -Warning 4207 Hint SUBQUERY(@`subq` INTOEXISTS) is ignored as conflicting/duplicated +Warning 4210 Hint SUBQUERY(@`subq` INTOEXISTS) is ignored as conflicting/duplicated Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq`) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,(((`test`.`t2`.`a`) in t1 on PRIMARY)))) EXPLAIN EXTENDED SELECT /*+ SEMIJOIN(@subq FIRSTMATCH) */ * FROM t2 @@ -1851,6 +1851,6 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index 2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index Warnings: -Warning 4207 Hint SEMIJOIN(@`subq` FIRSTMATCH) is ignored as conflicting/duplicated +Warning 4210 Hint SEMIJOIN(@`subq` FIRSTMATCH) is ignored as conflicting/duplicated Note 1003 /* select#1 */ select /*+ SUBQUERY(@`subq` INTOEXISTS) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,(((`test`.`t2`.`a`) in t1 on PRIMARY)))) DROP TABLE t1,t2,t3; diff --git a/mysql-test/main/opt_trace.result b/mysql-test/main/opt_trace.result index bdb7b9718be..023b9bd2db6 100644 --- a/mysql-test/main/opt_trace.result +++ b/mysql-test/main/opt_trace.result @@ -88,16 +88,6 @@ select * from v1 { ] } }, - { - "table_dependencies": [ - { - "table": "t1", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - } - ] - }, { "ref_optimizer_key_uses": [] }, @@ -124,6 +114,16 @@ select * from v1 { } ] }, + { + "table_dependencies": [ + { + "table": "t1", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + } + ] + }, { "considered_execution_plans": [ { @@ -259,16 +259,6 @@ select * from (select * from t1 where t1.a=1)q { ] } }, - { - "table_dependencies": [ - { - "table": "t1", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - } - ] - }, { "ref_optimizer_key_uses": [] }, @@ -295,6 +285,16 @@ select * from (select * from t1 where t1.a=1)q { } ] }, + { + "table_dependencies": [ + { + "table": "t1", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + } + ] + }, { "considered_execution_plans": [ { @@ -435,16 +435,6 @@ select * from v2 { ] } }, - { - "table_dependencies": [ - { - "table": "t1", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - } - ] - }, { "ref_optimizer_key_uses": [] }, @@ -471,6 +461,16 @@ select * from v2 { } ] }, + { + "table_dependencies": [ + { + "table": "t1", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + } + ] + }, { "considered_execution_plans": [ { @@ -567,16 +567,6 @@ select * from v2 { ] } }, - { - "table_dependencies": [ - { - "table": "", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - } - ] - }, { "rows_estimation": [ { @@ -589,6 +579,16 @@ select * from v2 { } ] }, + { + "table_dependencies": [ + { + "table": "", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + } + ] + }, { "considered_execution_plans": [ { @@ -724,16 +724,6 @@ explain select * from v2 { "join_optimization": { "select_id": 1, "steps": [ - { - "table_dependencies": [ - { - "table": "t2", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - } - ] - }, { "rows_estimation": [ { @@ -746,6 +736,16 @@ explain select * from v2 { } ] }, + { + "table_dependencies": [ + { + "table": "t2", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + } + ] + }, { "considered_execution_plans": [ { @@ -860,16 +860,6 @@ explain select * from v1 { "join_optimization": { "select_id": 2, "steps": [ - { - "table_dependencies": [ - { - "table": "t1", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - } - ] - }, { "rows_estimation": [ { @@ -882,6 +872,16 @@ explain select * from v1 { } ] }, + { + "table_dependencies": [ + { + "table": "t1", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + } + ] + }, { "considered_execution_plans": [ { @@ -973,16 +973,6 @@ explain select * from v1 { ] } }, - { - "table_dependencies": [ - { - "table": "", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - } - ] - }, { "rows_estimation": [ { @@ -995,6 +985,16 @@ explain select * from v1 { } ] }, + { + "table_dependencies": [ + { + "table": "", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + } + ] + }, { "considered_execution_plans": [ { @@ -1134,22 +1134,6 @@ explain select * from t1,t2 where t1.a=t2.b+2 and t2.a= t1.b { ] } }, - { - "table_dependencies": [ - { - "table": "t1", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - }, - { - "table": "t2", - "row_may_be_null": false, - "map_bit": 1, - "depends_on_map_bits": [] - } - ] - }, { "ref_optimizer_key_uses": [ { @@ -1188,6 +1172,22 @@ explain select * from t1,t2 where t1.a=t2.b+2 and t2.a= t1.b { } ] }, + { + "table_dependencies": [ + { + "table": "t1", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + }, + { + "table": "t2", + "row_may_be_null": false, + "map_bit": 1, + "depends_on_map_bits": [] + } + ] + }, { "considered_execution_plans": [ { @@ -1433,16 +1433,6 @@ EXPLAIN SELECT DISTINCT a FROM t1 { "join_optimization": { "select_id": 1, "steps": [ - { - "table_dependencies": [ - { - "table": "t1", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - } - ] - }, { "rows_estimation": [ { @@ -1514,6 +1504,16 @@ EXPLAIN SELECT DISTINCT a FROM t1 { } ] }, + { + "table_dependencies": [ + { + "table": "t1", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + } + ] + }, { "considered_execution_plans": [ { @@ -1641,16 +1641,6 @@ set statement optimizer_scan_setup_cost=0 for EXPLAIN SELECT MIN(d) FROM t1 wher ] } }, - { - "table_dependencies": [ - { - "table": "t1", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - } - ] - }, { "ref_optimizer_key_uses": [] }, @@ -1729,6 +1719,16 @@ set statement optimizer_scan_setup_cost=0 for EXPLAIN SELECT MIN(d) FROM t1 wher } ] }, + { + "table_dependencies": [ + { + "table": "t1", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + } + ] + }, { "considered_execution_plans": [ { @@ -1895,16 +1895,6 @@ EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104e0 GROUP BY id { ] } }, - { - "table_dependencies": [ - { - "table": "t1", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - } - ] - }, { "ref_optimizer_key_uses": [] }, @@ -1982,6 +1972,16 @@ EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104e0 GROUP BY id { } ] }, + { + "table_dependencies": [ + { + "table": "t1", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + } + ] + }, { "considered_execution_plans": [ { @@ -2116,16 +2116,6 @@ EXPLAIN SELECT * FROM t1 WHERE a = 20010104e0 GROUP BY id { ] } }, - { - "table_dependencies": [ - { - "table": "t1", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - } - ] - }, { "ref_optimizer_key_uses": [] }, @@ -2203,6 +2193,16 @@ EXPLAIN SELECT * FROM t1 WHERE a = 20010104e0 GROUP BY id { } ] }, + { + "table_dependencies": [ + { + "table": "t1", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + } + ] + }, { "considered_execution_plans": [ { @@ -2351,16 +2351,6 @@ explain select * from t1 where a=1 and b=2 order by c limit 1 { ] } }, - { - "table_dependencies": [ - { - "table": "t1", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - } - ] - }, { "ref_optimizer_key_uses": [ { @@ -2497,6 +2487,16 @@ explain select * from t1 where a=1 and b=2 order by c limit 1 { } ] }, + { + "table_dependencies": [ + { + "table": "t1", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + } + ] + }, { "considered_execution_plans": [ { @@ -2738,22 +2738,6 @@ select t1.a from t1 left join t2 on t1.a=t2.a { "resulting_condition": "multiple equal(t1.a, t2.a)" } }, - { - "table_dependencies": [ - { - "table": "t1", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - }, - { - "table": "t2", - "row_may_be_null": true, - "map_bit": 1, - "depends_on_map_bits": ["0"] - } - ] - }, { "ref_optimizer_key_uses": [ { @@ -2786,6 +2770,22 @@ select t1.a from t1 left join t2 on t1.a=t2.a { } ] }, + { + "table_dependencies": [ + { + "table": "t1", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + }, + { + "table": "t2", + "row_may_be_null": true, + "map_bit": 1, + "depends_on_map_bits": ["0"] + } + ] + }, { "considered_execution_plans": [ { @@ -2898,22 +2898,6 @@ explain select * from t1 left join t2 on t2.a=t1.a { "resulting_condition": "multiple equal(t2.a, t1.a)" } }, - { - "table_dependencies": [ - { - "table": "t1", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - }, - { - "table": "t2", - "row_may_be_null": true, - "map_bit": 1, - "depends_on_map_bits": ["0"] - } - ] - }, { "ref_optimizer_key_uses": [ { @@ -2948,6 +2932,22 @@ explain select * from t1 left join t2 on t2.a=t1.a { } ] }, + { + "table_dependencies": [ + { + "table": "t1", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + }, + { + "table": "t2", + "row_may_be_null": true, + "map_bit": 1, + "depends_on_map_bits": ["0"] + } + ] + }, { "considered_execution_plans": [ { @@ -3112,28 +3112,6 @@ explain select t1.a from t1 left join (t2 join t3 on t2.b=t3.b) on t2.a=t1.a and "resulting_condition": "multiple equal(t2.a, t1.a, t3.a) and multiple equal(t2.b, t3.b)" } }, - { - "table_dependencies": [ - { - "table": "t1", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - }, - { - "table": "t2", - "row_may_be_null": true, - "map_bit": 1, - "depends_on_map_bits": ["0"] - }, - { - "table": "t3", - "row_may_be_null": true, - "map_bit": 2, - "depends_on_map_bits": ["0"] - } - ] - }, { "ref_optimizer_key_uses": [ { @@ -3193,6 +3171,28 @@ explain select t1.a from t1 left join (t2 join t3 on t2.b=t3.b) on t2.a=t1.a and } ] }, + { + "table_dependencies": [ + { + "table": "t1", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + }, + { + "table": "t2", + "row_may_be_null": true, + "map_bit": 1, + "depends_on_map_bits": ["0"] + }, + { + "table": "t3", + "row_may_be_null": true, + "map_bit": 2, + "depends_on_map_bits": ["0"] + } + ] + }, { "considered_execution_plans": [ { @@ -3370,22 +3370,6 @@ explain extended select * from t1 where a in (select p from t2) { ] } }, - { - "table_dependencies": [ - { - "table": "t1", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - }, - { - "table": "t2", - "row_may_be_null": false, - "map_bit": 1, - "depends_on_map_bits": [] - } - ] - }, { "ref_optimizer_key_uses": [] }, @@ -3414,6 +3398,22 @@ explain extended select * from t1 where a in (select p from t2) { "pulled_out_tables": [] } }, + { + "table_dependencies": [ + { + "table": "t1", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + }, + { + "table": "t2", + "row_may_be_null": false, + "map_bit": 1, + "depends_on_map_bits": [] + } + ] + }, { "execution_plan_for_potential_materialization": { "steps": [ @@ -3720,16 +3720,6 @@ explain select * from t1 where pk = 2 and a=5 and b=1 { ] } }, - { - "table_dependencies": [ - { - "table": "t1", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - } - ] - }, { "ref_optimizer_key_uses": [ { @@ -3935,6 +3925,16 @@ explain select * from t1 where pk = 2 and a=5 and b=1 { } ] }, + { + "table_dependencies": [ + { + "table": "t1", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + } + ] + }, { "considered_execution_plans": [ { @@ -4081,16 +4081,6 @@ select f1(a) from t1 { "join_optimization": { "select_id": 1, "steps": [ - { - "table_dependencies": [ - { - "table": "t1", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - } - ] - }, { "rows_estimation": [ { @@ -4103,6 +4093,16 @@ select f1(a) from t1 { } ] }, + { + "table_dependencies": [ + { + "table": "t1", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + } + ] + }, { "considered_execution_plans": [ { @@ -4198,16 +4198,6 @@ select f2(a) from t1 { "join_optimization": { "select_id": 1, "steps": [ - { - "table_dependencies": [ - { - "table": "t1", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - } - ] - }, { "rows_estimation": [ { @@ -4220,6 +4210,16 @@ select f2(a) from t1 { } ] }, + { + "table_dependencies": [ + { + "table": "t1", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + } + ] + }, { "considered_execution_plans": [ { @@ -4464,22 +4464,6 @@ explain delete t0,t1 from t0, t1 where t0.a=t1.a and t1.a<3 { ] } }, - { - "table_dependencies": [ - { - "table": "t0", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - }, - { - "table": "t1", - "row_may_be_null": false, - "map_bit": 1, - "depends_on_map_bits": [] - } - ] - }, { "ref_optimizer_key_uses": [ { @@ -4652,6 +4636,22 @@ explain delete t0,t1 from t0, t1 where t0.a=t1.a and t1.a<3 { } ] }, + { + "table_dependencies": [ + { + "table": "t0", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + }, + { + "table": "t1", + "row_may_be_null": false, + "map_bit": 1, + "depends_on_map_bits": [] + } + ] + }, { "considered_execution_plans": [ { @@ -4908,16 +4908,6 @@ explain select * from (select rand() from t1)q { "join_optimization": { "select_id": 2, "steps": [ - { - "table_dependencies": [ - { - "table": "t1", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - } - ] - }, { "rows_estimation": [ { @@ -4930,6 +4920,16 @@ explain select * from (select rand() from t1)q { } ] }, + { + "table_dependencies": [ + { + "table": "t1", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + } + ] + }, { "considered_execution_plans": [ { @@ -4993,16 +4993,6 @@ explain select * from (select rand() from t1)q { ] } }, - { - "table_dependencies": [ - { - "table": "", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - } - ] - }, { "rows_estimation": [ { @@ -5015,6 +5005,16 @@ explain select * from (select rand() from t1)q { } ] }, + { + "table_dependencies": [ + { + "table": "", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + } + ] + }, { "considered_execution_plans": [ { @@ -5183,28 +5183,6 @@ explain select * from t1 where a in (select t_inner_1.a from t1 t_inner_1, t1 t_ ] } }, - { - "table_dependencies": [ - { - "table": "t1", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - }, - { - "table": "t_inner_1", - "row_may_be_null": false, - "map_bit": 1, - "depends_on_map_bits": [] - }, - { - "table": "t_inner_2", - "row_may_be_null": false, - "map_bit": 2, - "depends_on_map_bits": [] - } - ] - }, { "ref_optimizer_key_uses": [] }, @@ -5241,6 +5219,28 @@ explain select * from t1 where a in (select t_inner_1.a from t1 t_inner_1, t1 t_ "pulled_out_tables": [] } }, + { + "table_dependencies": [ + { + "table": "t1", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + }, + { + "table": "t_inner_1", + "row_may_be_null": false, + "map_bit": 1, + "depends_on_map_bits": [] + }, + { + "table": "t_inner_2", + "row_may_be_null": false, + "map_bit": 2, + "depends_on_map_bits": [] + } + ] + }, { "execution_plan_for_potential_materialization": { "steps": [ @@ -5804,46 +5804,6 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) { ] } }, - { - "table_dependencies": [ - { - "table": "t_outer_1", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - }, - { - "table": "t_outer_2", - "row_may_be_null": false, - "map_bit": 1, - "depends_on_map_bits": [] - }, - { - "table": "t_inner_2", - "row_may_be_null": false, - "map_bit": 2, - "depends_on_map_bits": [] - }, - { - "table": "t_inner_1", - "row_may_be_null": false, - "map_bit": 3, - "depends_on_map_bits": [] - }, - { - "table": "t_inner_3", - "row_may_be_null": false, - "map_bit": 4, - "depends_on_map_bits": [] - }, - { - "table": "t_inner_4", - "row_may_be_null": false, - "map_bit": 5, - "depends_on_map_bits": [] - } - ] - }, { "ref_optimizer_key_uses": [] }, @@ -5909,6 +5869,46 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) { "pulled_out_tables": [] } }, + { + "table_dependencies": [ + { + "table": "t_outer_1", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + }, + { + "table": "t_outer_2", + "row_may_be_null": false, + "map_bit": 1, + "depends_on_map_bits": [] + }, + { + "table": "t_inner_2", + "row_may_be_null": false, + "map_bit": 2, + "depends_on_map_bits": [] + }, + { + "table": "t_inner_1", + "row_may_be_null": false, + "map_bit": 3, + "depends_on_map_bits": [] + }, + { + "table": "t_inner_3", + "row_may_be_null": false, + "map_bit": 4, + "depends_on_map_bits": [] + }, + { + "table": "t_inner_4", + "row_may_be_null": false, + "map_bit": 5, + "depends_on_map_bits": [] + } + ] + }, { "execution_plan_for_potential_materialization": { "steps": [] @@ -8212,46 +8212,6 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) { ] } }, - { - "table_dependencies": [ - { - "table": "t_outer_1", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - }, - { - "table": "t_outer_2", - "row_may_be_null": false, - "map_bit": 1, - "depends_on_map_bits": [] - }, - { - "table": "t_inner_2", - "row_may_be_null": false, - "map_bit": 2, - "depends_on_map_bits": [] - }, - { - "table": "t_inner_1", - "row_may_be_null": false, - "map_bit": 3, - "depends_on_map_bits": [] - }, - { - "table": "t_inner_3", - "row_may_be_null": false, - "map_bit": 4, - "depends_on_map_bits": [] - }, - { - "table": "t_inner_4", - "row_may_be_null": false, - "map_bit": 5, - "depends_on_map_bits": [] - } - ] - }, { "ref_optimizer_key_uses": [] }, @@ -8317,6 +8277,46 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) { "pulled_out_tables": [] } }, + { + "table_dependencies": [ + { + "table": "t_outer_1", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + }, + { + "table": "t_outer_2", + "row_may_be_null": false, + "map_bit": 1, + "depends_on_map_bits": [] + }, + { + "table": "t_inner_2", + "row_may_be_null": false, + "map_bit": 2, + "depends_on_map_bits": [] + }, + { + "table": "t_inner_1", + "row_may_be_null": false, + "map_bit": 3, + "depends_on_map_bits": [] + }, + { + "table": "t_inner_3", + "row_may_be_null": false, + "map_bit": 4, + "depends_on_map_bits": [] + }, + { + "table": "t_inner_4", + "row_may_be_null": false, + "map_bit": 5, + "depends_on_map_bits": [] + } + ] + }, { "execution_plan_for_potential_materialization": { "steps": [ @@ -11902,22 +11902,6 @@ UPDATE t, v SET t.b = t.a, t.a = v.c WHERE v.c < t.a { "steps": [] } }, - { - "table_dependencies": [ - { - "table": "t", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - }, - { - "table": "", - "row_may_be_null": false, - "map_bit": 1, - "depends_on_map_bits": [] - } - ] - }, { "ref_optimizer_key_uses": [] }, @@ -11941,6 +11925,22 @@ UPDATE t, v SET t.b = t.a, t.a = v.c WHERE v.c < t.a { } ] }, + { + "table_dependencies": [ + { + "table": "t", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + }, + { + "table": "", + "row_may_be_null": false, + "map_bit": 1, + "depends_on_map_bits": [] + } + ] + }, { "considered_execution_plans": [ { @@ -12149,16 +12149,6 @@ UPDATE t, v SET t.b = t.a, t.a = v.c WHERE v.c < t.a { "join_optimization": { "select_id": "fake", "steps": [ - { - "table_dependencies": [ - { - "table": "union", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - } - ] - }, { "rows_estimation": [ { @@ -12171,6 +12161,16 @@ UPDATE t, v SET t.b = t.a, t.a = v.c WHERE v.c < t.a { } ] }, + { + "table_dependencies": [ + { + "table": "union", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + } + ] + }, { "considered_execution_plans": [ { @@ -12409,16 +12409,6 @@ select count(*) from seq_1_to_10000000 { "join_optimization": { "select_id": 1, "steps": [ - { - "table_dependencies": [ - { - "table": "seq_1_to_10000000", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - } - ] - }, { "rows_estimation": [ { @@ -12431,6 +12421,16 @@ select count(*) from seq_1_to_10000000 { } ] }, + { + "table_dependencies": [ + { + "table": "seq_1_to_10000000", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + } + ] + }, { "considered_execution_plans": [ { @@ -13043,16 +13043,6 @@ explain select * from t1 where a<10 and b between 10 and 50 and c < 10 { ] } }, - { - "table_dependencies": [ - { - "table": "t1", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - } - ] - }, { "ref_optimizer_key_uses": [] }, @@ -13161,6 +13151,16 @@ explain select * from t1 where a<10 and b between 10 and 50 and c < 10 { } ] }, + { + "table_dependencies": [ + { + "table": "t1", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + } + ] + }, { "considered_execution_plans": [ { @@ -13438,22 +13438,6 @@ explain format=json select * from three, t1 where t1.a=three.a and t1.b<5000 and ] } }, - { - "table_dependencies": [ - { - "table": "three", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - }, - { - "table": "t1", - "row_may_be_null": false, - "map_bit": 1, - "depends_on_map_bits": [] - } - ] - }, { "ref_optimizer_key_uses": [ { @@ -13548,6 +13532,22 @@ explain format=json select * from three, t1 where t1.a=three.a and t1.b<5000 and } ] }, + { + "table_dependencies": [ + { + "table": "three", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + }, + { + "table": "t1", + "row_may_be_null": false, + "map_bit": 1, + "depends_on_map_bits": [] + } + ] + }, { "considered_execution_plans": [ { diff --git a/mysql-test/main/opt_trace_index_merge.result b/mysql-test/main/opt_trace_index_merge.result index 70db13798a7..2ad39304ebe 100644 --- a/mysql-test/main/opt_trace_index_merge.result +++ b/mysql-test/main/opt_trace_index_merge.result @@ -53,16 +53,6 @@ explain select * from t1 where a=1 or b=1 { ] } }, - { - "table_dependencies": [ - { - "table": "t1", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - } - ] - }, { "ref_optimizer_key_uses": [] }, @@ -205,6 +195,16 @@ explain select * from t1 where a=1 or b=1 { } ] }, + { + "table_dependencies": [ + { + "table": "t1", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + } + ] + }, { "considered_execution_plans": [ { diff --git a/mysql-test/main/opt_trace_index_merge_innodb.result b/mysql-test/main/opt_trace_index_merge_innodb.result index 02509aa9610..e5263f7bbd7 100644 --- a/mysql-test/main/opt_trace_index_merge_innodb.result +++ b/mysql-test/main/opt_trace_index_merge_innodb.result @@ -61,16 +61,6 @@ explain select * from t1 where pk1 != 0 and key1 = 1 { ] } }, - { - "table_dependencies": [ - { - "table": "t1", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - } - ] - }, { "ref_optimizer_key_uses": [ { @@ -199,6 +189,16 @@ explain select * from t1 where pk1 != 0 and key1 = 1 { } ] }, + { + "table_dependencies": [ + { + "table": "t1", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + } + ] + }, { "considered_execution_plans": [ { diff --git a/mysql-test/main/opt_trace_security.result b/mysql-test/main/opt_trace_security.result index cf5dcf5d886..8b483cf458b 100644 --- a/mysql-test/main/opt_trace_security.result +++ b/mysql-test/main/opt_trace_security.result @@ -64,16 +64,6 @@ select * from db1.t1 { "join_optimization": { "select_id": 1, "steps": [ - { - "table_dependencies": [ - { - "table": "t1", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - } - ] - }, { "rows_estimation": [ { @@ -86,6 +76,16 @@ select * from db1.t1 { } ] }, + { + "table_dependencies": [ + { + "table": "t1", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + } + ] + }, { "considered_execution_plans": [ { @@ -206,16 +206,6 @@ select * from db1.v1 { "join_optimization": { "select_id": 1, "steps": [ - { - "table_dependencies": [ - { - "table": "t1", - "row_may_be_null": false, - "map_bit": 0, - "depends_on_map_bits": [] - } - ] - }, { "rows_estimation": [ { @@ -228,6 +218,16 @@ select * from db1.v1 { } ] }, + { + "table_dependencies": [ + { + "table": "t1", + "row_may_be_null": false, + "map_bit": 0, + "depends_on_map_bits": [] + } + ] + }, { "considered_execution_plans": [ { diff --git a/sql/opt_hints.cc b/sql/opt_hints.cc index 097983feb7b..1a6038aa17c 100644 --- a/sql/opt_hints.cc +++ b/sql/opt_hints.cc @@ -32,16 +32,20 @@ struct st_opt_hint_info opt_hint_info[]= { - {{STRING_WITH_LEN("BKA")}, true, false}, - {{STRING_WITH_LEN("BNL")}, true, false}, - {{STRING_WITH_LEN("ICP")}, true, false}, - {{STRING_WITH_LEN("MRR")}, true, false}, - {{STRING_WITH_LEN("NO_RANGE_OPTIMIZATION")}, true, false}, - {{STRING_WITH_LEN("QB_NAME")}, false, false}, - {{STRING_WITH_LEN("MAX_EXECUTION_TIME")}, false, true}, - {{STRING_WITH_LEN("SEMIJOIN")}, false, true}, - {{STRING_WITH_LEN("SUBQUERY")}, false, true}, - {null_clex_str, 0, 0} + {{STRING_WITH_LEN("BKA")}, true, false, false}, + {{STRING_WITH_LEN("BNL")}, true, false, false}, + {{STRING_WITH_LEN("ICP")}, true, false, false}, + {{STRING_WITH_LEN("MRR")}, true, false, false}, + {{STRING_WITH_LEN("NO_RANGE_OPTIMIZATION")}, true, false, false}, + {{STRING_WITH_LEN("QB_NAME")}, false, false, false}, + {{STRING_WITH_LEN("MAX_EXECUTION_TIME")}, false, true, false}, + {{STRING_WITH_LEN("SEMIJOIN")}, false, true, false}, + {{STRING_WITH_LEN("SUBQUERY")}, false, true, false}, + {{STRING_WITH_LEN("JOIN_PREFIX")}, false, true, true}, + {{STRING_WITH_LEN("JOIN_SUFFIX")}, false, true, true}, + {{STRING_WITH_LEN("JOIN_ORDER")}, false, true, true}, + {{STRING_WITH_LEN("JOIN_FIXED_ORDER")}, false, true, false}, + {null_clex_str, 0, 0, 0} }; /** @@ -51,9 +55,6 @@ struct st_opt_hint_info opt_hint_info[]= const LEX_CSTRING sys_qb_prefix= {"select#", 7}; -static const Lex_ident_sys null_ident_sys; - -static void print_warn(THD *thd, uint err_code, opt_hints_enum hint_type, bool hint_state, const Lex_ident_sys *qb_name_arg, @@ -146,7 +147,7 @@ void print_warn(THD *thd, uint err_code, opt_hints_enum hint_type, NULL if failed to create the object */ -static Opt_hints_global *get_global_hints(Parse_context *pc) +Opt_hints_global *get_global_hints(Parse_context *pc) { LEX *lex= pc->thd->lex; @@ -159,7 +160,7 @@ static Opt_hints_global *get_global_hints(Parse_context *pc) } -static Opt_hints_qb *get_qb_hints(Parse_context *pc) +Opt_hints_qb *get_qb_hints(Parse_context *pc) { if (pc->select->opt_hints_qb) return pc->select->opt_hints_qb; @@ -197,10 +198,10 @@ static Opt_hints_qb *get_qb_hints(Parse_context *pc) NULL otherwise */ -static Opt_hints_qb *find_qb_hints(Parse_context *pc, - const Lex_ident_sys &qb_name, - opt_hints_enum hint_type, - bool hint_state) +Opt_hints_qb *find_qb_hints(Parse_context *pc, + const Lex_ident_sys &qb_name, + opt_hints_enum hint_type, + bool hint_state) { if (qb_name.length == 0) // no QB NAME is used return pc->select->opt_hints_qb; @@ -229,9 +230,9 @@ static Opt_hints_qb *find_qb_hints(Parse_context *pc, NULL if failed to create the object */ -static Opt_hints_table *get_table_hints(Parse_context *pc, - const Lex_ident_sys &table_name, - Opt_hints_qb *qb) +Opt_hints_table *get_table_hints(Parse_context *pc, + const Lex_ident_sys &table_name, + Opt_hints_qb *qb) { Opt_hints_table *tab= static_cast (qb->find_by_name(table_name)); @@ -280,9 +281,12 @@ void Opt_hints::print(THD *thd, String *str) // Print the hints stored in the bitmap for (uint i= 0; i < MAX_HINT_ENUM; i++) { - if (is_specified(static_cast(i))) + if (opt_hint_info[i].irregular_hint) + continue; + opt_hints_enum hint_type= static_cast(i); + if (is_specified(hint_type)) { - append_hint_type(str, static_cast(i)); + append_hint_type(str, hint_type); str->append(STRING_WITH_LEN("(")); uint32 len_before_name= str->length(); append_name(thd, str); @@ -290,7 +294,7 @@ void Opt_hints::print(THD *thd, String *str) if (len_after_name > len_before_name) str->append(' '); if (opt_hint_info[i].has_arguments) - append_hint_arguments(thd, static_cast(i), str); + append_hint_arguments(thd, hint_type, str); if (str->length() == len_after_name + 1) { // No additional arguments were printed, trim the space added before @@ -300,6 +304,8 @@ void Opt_hints::print(THD *thd, String *str) } } + print_irregular_hints(thd, str); + for (uint i= 0; i < child_array.size(); i++) child_array[i]->print(thd, str); } @@ -361,10 +367,12 @@ Opt_hints_qb::Opt_hints_qb(Opt_hints *opt_hints_arg, MEM_ROOT *mem_root_arg, uint select_number_arg) : Opt_hints(Lex_ident_sys(), opt_hints_arg, mem_root_arg), - select_number(select_number_arg) + select_number(select_number_arg), + join_order_hints(mem_root_arg), + join_order_hints_ignored(0) { sys_name.str= buff; - sys_name.length= my_snprintf(buff, sizeof(buff), "%s%lx", + sys_name.length= my_snprintf(buff, sizeof(buff), "%s%x", sys_qb_prefix.str, select_number); } @@ -425,6 +433,26 @@ uint Opt_hints_qb::sj_enabled_strategies(uint opt_switches) const } +void Opt_hints_qb::append_hint_arguments(THD *thd, opt_hints_enum hint, + String *str) +{ + switch (hint) + { + case SUBQUERY_HINT_ENUM: + subquery_hint->append_args(thd, str); + break; + case SEMIJOIN_HINT_ENUM: + semijoin_hint->append_args(thd, str); + break; + case JOIN_FIXED_ORDER_HINT_ENUM: + join_fixed_order->append_args(thd, str); + break; + default: + DBUG_ASSERT(0); + } +} + + /* @brief For each index IDX, put its hints into keyinfo_array[IDX] @@ -559,562 +587,345 @@ bool hint_table_state(const THD *thd, const TABLE *table, return fallback_value; } -/* - Resolve a parsed table level hint, i.e. set up proper Opt_hint_* structures - which will be used later during query preparation and optimization. - Return value: - - false: no critical errors, warnings on duplicated hints, - unresolved query block names, etc. are allowed - - true: critical errors detected, break further hints processing -*/ -bool Parser::Table_level_hint::resolve(Parse_context *pc) const +void append_table_name(THD *thd, String *str, const LEX_CSTRING &table_name, + const LEX_CSTRING &qb_name) { - const Table_level_hint_type &table_level_hint_type= *this; - opt_hints_enum hint_type; - bool hint_state; // ON or OFF + /* Append table name */ + append_identifier(thd, str, &table_name); - switch (table_level_hint_type.id()) + /* Append QB name */ + if (qb_name.length > 0) { - case TokenID::keyword_BNL: - hint_type= BNL_HINT_ENUM; - hint_state= true; - break; - case TokenID::keyword_NO_BNL: - hint_type= BNL_HINT_ENUM; - hint_state= false; - break; - case TokenID::keyword_BKA: - hint_type= BKA_HINT_ENUM; - hint_state= true; - break; - case TokenID::keyword_NO_BKA: - hint_type= BKA_HINT_ENUM; - hint_state= false; - break; - default: - DBUG_ASSERT(0); - return true; + str->append(STRING_WITH_LEN("@")); + append_identifier(thd, str, &qb_name); + } +} + + +void Opt_hints_qb::apply_join_order_hints(JOIN *join) +{ + if (join_fixed_order) + { + DBUG_ASSERT(join_order_hints.size() == 0 && !join_prefix && !join_suffix); + // The hint is already applied at Parser::Join_order_hint::resolve() + return; + } + DBUG_ASSERT(!join_fixed_order); + + // Apply hints in the same order they were specified in the query + for (uint hint_idx= 0; hint_idx < join_order_hints.size(); hint_idx++) + { + Parser::Join_order_hint* hint= join_order_hints[hint_idx]; + if (join->select_options & SELECT_STRAIGHT_JOIN) + { + // Only mark as ignored and print the warning + join_order_hints_ignored |= 1ULL << hint_idx; + print_warn(join->thd, ER_WARN_CONFLICTING_HINT, hint->hint_type, true, + nullptr, nullptr, nullptr, hint); + } + else if (set_join_hint_deps(join, hint)) + { + // Mark as ignored + join_order_hints_ignored |= 1ULL << hint_idx; + } + } +} + + +/** + @brief + Resolve hint tables, check and set table dependencies according to one + JOIN_ORDER, JOIN_PREFIX, or JOIN_SUFFIX hint. + + @param join pointer to JOIN object + @param hint The hint + + @detail + If the hint is ignored due to circular table dependencies, original + dependencies are restored and a warning is generated. + + == Dependencies that we add == + For any JOIN_HINT(t1, t2, t3, t4) we add the these dependencies: + + t2.dependent|= {t1} + t3.dependent|= {t1,t2} + t4.dependent|= {t1,t2,t3} + and so forth. + + This makes sure that the listed tables occur in the join order in the order + they are listed in the hint. + + For JOIN_ORDER, this is all what we need. + For JOIN_PREFIX(t1, t2, ...) we also add dependencies on {t1,t2,...} + for all tables not listed in the hint. + For JOIN_SUFFIX(t1, t2, ...) dependencies on all tables that are NOT listed + in the hint are added to all tables LISTED in the hint: {t1, t2, ...} + + @return false if hint is applied, true otherwise. +*/ + +bool Opt_hints_qb::set_join_hint_deps(JOIN *join, + const Parser::Join_order_hint *hint) +{ + /* + Make a copy of original table dependencies. If an error occurs + when applying the hint, the original dependencies will be restored. + */ + table_map *orig_dep_array= join->export_table_dependencies(); + + // Map of the tables, specified in the hint + table_map hint_tab_map= 0; + + for (const Parser::Table_name_and_Qb& tbl_name_and_qb : hint->table_names) + { + bool hint_table_found= false; + for (uint i= 0; i < join->table_count; i++) + { + TABLE_LIST *table= join->join_tab[i].tab_list; + if (!compare_table_name(&tbl_name_and_qb, table)) + { + hint_table_found= true; + /* + Const tables are excluded from the process of dependency setting + since they are always first in the table order. Note that it + does not prevent the hint from being applied to the non-const tables + */ + if (join->const_table_map & table->get_map()) + break; + + JOIN_TAB *join_tab= &join->join_tab[i]; + // Hint tables are always dependent on preceding tables + join_tab->dependent |= hint_tab_map; + update_nested_join_deps(join, join_tab, hint_tab_map); + hint_tab_map |= join_tab->tab_list->get_map(); + break; + } + } + + if (!hint_table_found) + { + print_join_order_warn(join->thd, hint->hint_type, tbl_name_and_qb); + join->restore_table_dependencies(orig_dep_array); + return true; + } } - if (const At_query_block_name_opt_table_name_list & - at_query_block_name_opt_table_name_list= *this) + // Add dependencies that are related to non-hint tables + for (uint i= 0; i < join->table_count; i++) { - // this is @ query_block_name opt_table_name_list - const Lex_ident_sys qb_name_sys= Query_block_name::to_ident_sys(pc->thd); - Opt_hints_qb *qb= find_qb_hints(pc, qb_name_sys, hint_type, hint_state); - if (qb == NULL) - return false; - if (at_query_block_name_opt_table_name_list.is_empty()) + JOIN_TAB *join_tab= &join->join_tab[i]; + const table_map dependent_tables= + get_other_dep(join, hint->hint_type, hint_tab_map, + join_tab->tab_list->get_map()); + update_nested_join_deps(join, join_tab, dependent_tables); + join_tab->dependent |= dependent_tables; + } + + if (join->propagate_dependencies(join->join_tab)) + { + join->restore_table_dependencies(orig_dep_array); + print_warn(join->thd, ER_WARN_CONFLICTING_HINT, hint->hint_type, true, + nullptr, nullptr, nullptr, hint); + return true; + } + return false; +} + + +/** + Function updates dependencies for nested joins. If a table + specified in the hint belongs to a nested join, we need + to update dependencies of all tables of the nested join + with the same dependency as for the hint table. It is also + necessary to update all tables of the nested joins this table + is part of. + + @param join pointer to JOIN object + @param hint_tab pointer to JOIN_TAB object + @param hint_tab_map map of the tables, specified in the hint + + + @detail + This function is called when the caller has added a dependency: + + hint_tab now also depends on hint_tab_map. + + For example: + + FROM t0 ... LEFT JOIN ( ... t1 ... t2 ... ) ON ... + + hint_tab=t1, hint_tab_map={t0}. + + We want to avoid the situation where the optimizer has constructed a join + prefix with table t2 and without table t0: + + ... t2 + + and now it needs to add t1 to the join prefix (it must do so, see + add_table_function_dependencies, check_interleaving_with_nj) but it can't + do that because t0 is not in the join prefix, and it's not possible to add + t0 as that would break the NO-INTERLEAVING rule (see mentioned functions) + + In order to avoid this situation, we make t2 also depend t0 (that is, also + depend on any tables outside the join nest that we've made t1 to depend on) + + Note that inside the join nest + + LEFT JOIN ( ... t1 ... t2 ... ) + + t1 and t2 may not be direct children but rather occur inside children join + nests: + + LEFT JOIN ( ... LEFT JOIN (...t1...) ... LEFT JOIN (...t2...) ... ) +*/ + +void Opt_hints_qb::update_nested_join_deps(JOIN *join, const JOIN_TAB *hint_tab, + table_map hint_tab_map) +{ + const TABLE_LIST *table= hint_tab->tab_list; + if (table->embedding) + { + for (uint i= 0; i < join->table_count; i++) { - // e.g. BKA(@qb1) - if (qb->set_switch(hint_state, hint_type, false)) + JOIN_TAB *tab= &join->join_tab[i]; + /* Walk up the nested joins that tab->table is a part of */ + for (TABLE_LIST *emb= tab->tab_list->embedding; emb; emb=emb->embedding) { - print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state, - &qb_name_sys, nullptr, nullptr, nullptr); - } - return false; - } - else - { - // e.g. BKA(@qb1 t1, t2, t3) - const Opt_table_name_list &opt_table_name_list= *this; - for (const Table_name &table : opt_table_name_list) - { - const Lex_ident_sys table_name_sys= table.to_ident_sys(pc->thd); - Opt_hints_table *tab= get_table_hints(pc, table_name_sys, qb); - if (!tab) - return false; - if (tab->set_switch(hint_state, hint_type, true)) + /* + Apply the rule only for outer joins. Semi-joins do not impose such + limitation + */ + if (emb->on_expr) { - print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state, - &qb_name_sys, &table_name_sys, nullptr, - nullptr); + const NESTED_JOIN *const nested_join= emb->nested_join; + /* Is hint_tab somewhere inside this nested join, too? */ + if (hint_tab->embedding_map & nested_join->nj_map) + { + /* + Yes, it is. Then, tab->table be also dependent on all outside + tables that hint_tab is dependent on: + */ + tab->dependent |= (hint_tab_map & ~nested_join->used_tables); + } } } } } - else - { - // this is opt_hint_param_table_list - const Opt_table_name_list &table_name_list= *this; - const Opt_hint_param_table_list &opt_hint_param_table_list= *this; - Opt_hints_qb *qb= find_qb_hints(pc, Lex_ident_sys(), hint_type, hint_state); - if (qb == NULL) - return false; - if (table_name_list.is_empty() && opt_hint_param_table_list.is_empty()) - { - // e.g. BKA() - if (qb->set_switch(hint_state, hint_type, false)) - { - print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state, - &null_ident_sys, nullptr, nullptr, nullptr); - } - return false; - } - for (const Table_name &table : table_name_list) - { - // e.g. BKA(t1, t2) - const Lex_ident_sys table_name_sys= table.to_ident_sys(pc->thd); - Opt_hints_table *tab= get_table_hints(pc, table_name_sys, qb); - if (!tab) - return false; - if (tab->set_switch(hint_state, hint_type, true)) - { - print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state, - &null_ident_sys, &table_name_sys, nullptr, nullptr); - } - } - - for (const Hint_param_table &table : opt_hint_param_table_list) - { - // e.g. BKA(t1@qb1, t2@qb2) - const Lex_ident_sys qb_name_sys= table.Query_block_name:: - to_ident_sys(pc->thd); - Opt_hints_qb *qb= find_qb_hints(pc, qb_name_sys, hint_type, hint_state); - if (qb == NULL) - return false; - const Lex_ident_sys table_name_sys= table.Table_name:: - to_ident_sys(pc->thd); - Opt_hints_table *tab= get_table_hints(pc, table_name_sys, qb); - if (!tab) - return false; - if (tab->set_switch(hint_state, hint_type, true)) - { - print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state, - &qb_name_sys, &table_name_sys, nullptr, nullptr); - } - } - } - return false; } -/* - Resolve a parsed index level hint, i.e. set up proper Opt_hint_* structures - which will be used later during query preparation and optimization. - Return value: - - false: no critical errors, warnings on duplicated hints, - unresolved query block names, etc. are allowed - - true: critical errors detected, break further hints processing +/** + Function returns a map of dependencies which must be applied to the + particular table of a JOIN, according to the join order hint + + @param join JOIN to which the hints are being applied + @param type hint type + @param hint_tab_map Bitmap of all tables listed in the hint. + @param table_map Bit of the table that we're setting extra dependencies + for. + + @detail + This returns extra dependencies between tables listed in the Hint and tables + that are not listed. Depending on hint type, these are: + + JOIN_PREFIX(t1, t2, ...) - all not listed tables depend on {t1,t2,...}. + + JOIN_SUFFIX(t1, t2, ...) - all tables listed in the hint depend on all tables + that are not listed in the hint + JOIN_ORDER(t1, t2, ...) - No extra dependencies needed. + + @return bitmap of dependencies to apply */ -bool Parser::Index_level_hint::resolve(Parse_context *pc) const + +table_map Opt_hints_qb:: + get_other_dep(JOIN *join, opt_hints_enum type, table_map hint_tab_map, + table_map table_map) { - const Index_level_hint_type &index_level_hint_type= *this; - opt_hints_enum hint_type; - bool hint_state; // ON or OFF - - switch (index_level_hint_type.id()) + switch (type) { - case TokenID::keyword_NO_ICP: - hint_type= ICP_HINT_ENUM; - hint_state= false; - break; - case TokenID::keyword_MRR: - hint_type= MRR_HINT_ENUM; - hint_state= true; - break; - case TokenID::keyword_NO_MRR: - hint_type= MRR_HINT_ENUM; - hint_state= false; - break; - case TokenID::keyword_NO_RANGE_OPTIMIZATION: - hint_type= NO_RANGE_HINT_ENUM; - hint_state= true; - break; - default: - DBUG_ASSERT(0); - return true; + case JOIN_PREFIX_HINT_ENUM: + if (hint_tab_map & table_map) // Hint table: No additional dependencies + return 0; + // Other tables: depend on all hint tables + return hint_tab_map; + case JOIN_SUFFIX_HINT_ENUM: + if (hint_tab_map & table_map) // Hint table: depends on all other tables + return join->all_tables_map() & ~hint_tab_map; + return 0; + case JOIN_ORDER_HINT_ENUM: + return 0; // No additional dependencies + default: + DBUG_ASSERT(0); + break; } - - const Hint_param_table_ext &table_ext= *this; - const Lex_ident_sys qb_name_sys= table_ext.Query_block_name:: - to_ident_sys(pc->thd); - const Lex_ident_sys table_name_sys= table_ext.Table_name:: - to_ident_sys(pc->thd); - Opt_hints_qb *qb= find_qb_hints(pc, qb_name_sys, hint_type, hint_state); - if (qb == NULL) - return false; - - Opt_hints_table *tab= get_table_hints(pc, table_name_sys, qb); - if (!tab) - return false; - - if (is_empty()) // Table level hint - { - if (tab->set_switch(hint_state, hint_type, false)) - { - print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state, - &qb_name_sys, &table_name_sys, nullptr, nullptr); - } - return false; - } - - for (const Hint_param_index &index_name : *this) - { - const Lex_ident_sys index_name_sys= index_name.to_ident_sys(pc->thd); - Opt_hints_key *idx= (Opt_hints_key *)tab->find_by_name(index_name_sys); - if (!idx) - { - idx= new (pc->thd->mem_root) - Opt_hints_key(index_name_sys, tab, pc->thd->mem_root); - tab->register_child(idx); - } - - if (idx->set_switch(hint_state, hint_type, true)) - { - print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state, - &qb_name_sys, &table_name_sys, &index_name_sys, nullptr); - } - } - return false; + return 0; } -/* - Resolve a parsed query block name hint, i.e. set up proper Opt_hint_* - structures which will be used later during query preparation and optimization. - Return value: - - false: no critical errors, warnings on duplicated hints, - unresolved query block names, etc. are allowed - - true: critical errors detected, break further hints processing +/** + Function compares hint table name and TABLE_LIST table name. + Query block name is taken into account also. + + @param hint_table_and_qb table/query block names given in the hint + @param table pointer to TABLE_LIST object + + @return false if table names are equal, true otherwise. */ -bool Parser::Qb_name_hint::resolve(Parse_context *pc) const + +bool Opt_hints_qb::compare_table_name( + const Parser::Table_name_and_Qb *hint_table_and_qb, + const TABLE_LIST *table) { - Opt_hints_qb *qb= pc->select->opt_hints_qb; + const LEX_CSTRING &join_tab_qb_name= + table->opt_hints_qb ? table->opt_hints_qb->get_name() : Lex_ident_sys(); - DBUG_ASSERT(qb); + /* + If QB name is not specified explicitly for a table name int hint, + for example `JOIN_PREFIX(t2)` or `JOIN_SUFFIX(@q1 t3)` then QB name is + considered to be equal to `Opt_hints_qb::get_name()` + */ + const LEX_CSTRING &hint_tab_qb_name= + hint_table_and_qb->qb_name.length > 0 ? hint_table_and_qb->qb_name : + this->get_name(); - const Lex_ident_sys qb_name_sys= Query_block_name::to_ident_sys(pc->thd); - - if (qb->get_name().str || // QB name is already set - qb->get_parent()->find_by_name(qb_name_sys)) // Name is already used - { - print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, QB_NAME_HINT_ENUM, true, - &qb_name_sys, nullptr, nullptr, nullptr); - return false; - } - - qb->set_name(qb_name_sys); - return false; + CHARSET_INFO *cs= charset_info(); + // Compare QB names + if (cs->strnncollsp(join_tab_qb_name, hint_tab_qb_name)) + return true; + // Compare table names + return cs->strnncollsp(table->alias, hint_table_and_qb->table_name); } -void Parser::Semijoin_hint::fill_strategies_map(Opt_hints_qb *qb) const +void Opt_hints_qb::print_irregular_hints(THD *thd, String *str) { - // Loop for hints like SEMIJOIN(firstmatch, dupsweedout) - const Hint_param_opt_sj_strategy_list &hint_param_strategy_list= *this; - for (const Semijoin_strategy &strat : hint_param_strategy_list) - add_strategy_to_map(strat.id(), qb); - - // Loop for hints like SEMIJOIN(@qb1 firstmatch, dupsweedout) - const Opt_sj_strategy_list &opt_sj_strategy_list= *this; - for (const Semijoin_strategy &strat : opt_sj_strategy_list) - add_strategy_to_map(strat.id(), qb); -} - - -void Parser::Semijoin_hint::add_strategy_to_map(TokenID token_id, - Opt_hints_qb *qb) const -{ - switch(token_id) + /* Print join order hints */ + for (uint i= 0; i < join_order_hints.size(); i++) { - case TokenID::keyword_DUPSWEEDOUT: - qb->semijoin_strategies_map |= OPTIMIZER_SWITCH_DUPSWEEDOUT; - break; - case TokenID::keyword_FIRSTMATCH: - qb->semijoin_strategies_map |= OPTIMIZER_SWITCH_FIRSTMATCH; - break; - case TokenID::keyword_LOOSESCAN: - qb->semijoin_strategies_map |= OPTIMIZER_SWITCH_LOOSE_SCAN; - break; - case TokenID::keyword_MATERIALIZATION: - qb->semijoin_strategies_map |= OPTIMIZER_SWITCH_MATERIALIZATION; - break; - default: - DBUG_ASSERT(0); - } -} - -/* - Resolve a parsed semijoin hint, i.e. set up proper Opt_hint_* structures - which will be used later during query preparation and optimization. - - Return value: - - false: no critical errors, warnings on duplicated hints, - unresolved query block names, etc. are allowed - - true: critical errors detected, break further hints processing -*/ -bool Parser::Semijoin_hint::resolve(Parse_context *pc) const -{ - const Semijoin_hint_type &semijoin_hint_type= *this; - bool hint_state; // true - SEMIJOIN(), false - NO_SEMIJOIN() - if (semijoin_hint_type.id() == TokenID::keyword_SEMIJOIN) - hint_state= true; - else - hint_state= false; - Opt_hints_qb *qb; - if (const At_query_block_name_opt_strategy_list & - at_query_block_name_opt_strategy_list __attribute__((unused)) = *this) - { - /* - This is @ query_block_name opt_strategy_list, - e.g. SEMIJOIN(@qb1) or SEMIJOIN(@qb1 firstmatch, loosescan) - */ - const Lex_ident_sys qb_name= Query_block_name::to_ident_sys(pc->thd); - qb= resolve_for_qb_name(pc, hint_state, &qb_name); - } - else - { - // This is opt_strategy_list, e.g. SEMIJOIN(loosescan, dupsweedout) - Lex_ident_sys empty_qb_name= Lex_ident_sys(); - qb= resolve_for_qb_name(pc, hint_state, &empty_qb_name); - } - if (qb) - qb->semijoin_hint= this; - return false; -} - - -/* - Helper function to be called by Semijoin_hint::resolve(). - - Return value: - - pointer to Opt_hints_qb if the hint was resolved successfully - - NULL if the hint was ignored -*/ -Opt_hints_qb* Parser::Semijoin_hint::resolve_for_qb_name(Parse_context *pc, - bool hint_state, const Lex_ident_sys *qb_name) const -{ - Opt_hints_qb *qb= find_qb_hints(pc, *qb_name, SEMIJOIN_HINT_ENUM, hint_state); - if (!qb) - return nullptr; - if (qb->subquery_hint) - { - print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, SEMIJOIN_HINT_ENUM, - hint_state, qb_name, nullptr, nullptr, this); - return nullptr; - } - if (qb->set_switch(hint_state, SEMIJOIN_HINT_ENUM, false)) - { - print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, SEMIJOIN_HINT_ENUM, - hint_state, qb_name, nullptr, nullptr, this); - return nullptr; - } - fill_strategies_map(qb); - return qb; -} - - -void Parser::Semijoin_hint::append_args(THD *thd, String *str) const -{ - // Loop for hints without query block name, e.g. SEMIJOIN(firstmatch, dupsweedout) - const Hint_param_opt_sj_strategy_list &hint_param_strategy_list= *this; - uint32 len_before= str->length(); - for (const Semijoin_strategy &strat : hint_param_strategy_list) - { - if (str->length() > len_before) - str->append(STRING_WITH_LEN(", ")); - append_strategy_name(strat.id(), str); - } - - // Loop for hints with query block name, e.g. SEMIJOIN(@qb1 firstmatch, dupsweedout) - const Opt_sj_strategy_list &opt_sj_strategy_list= *this; - for (const Semijoin_strategy &strat : opt_sj_strategy_list) - { - if (str->length() > len_before) - str->append(STRING_WITH_LEN(", ")); - append_strategy_name(strat.id(), str); + if (join_order_hints_ignored & (1ULL << i)) + continue; + const Parser::Join_order_hint *hint= join_order_hints[i]; + str->append(opt_hint_info[hint->hint_type].hint_type); + str->append(STRING_WITH_LEN("(")); + append_name(thd, str); + str->append(STRING_WITH_LEN(" ")); + hint->append_args(thd, str); + str->append(STRING_WITH_LEN(") ")); } } -void Parser::Semijoin_hint:: - append_strategy_name(TokenID token_id, String *str) const +void Opt_hints_qb::print_join_order_warn(THD *thd, opt_hints_enum type, + const Parser::Table_name_and_Qb &tbl_name) { - switch(token_id) - { - case TokenID::keyword_DUPSWEEDOUT: - str->append(STRING_WITH_LEN("DUPSWEEDOUT")); - break; - case TokenID::keyword_FIRSTMATCH: - str->append(STRING_WITH_LEN("FIRSTMATCH")); - break; - case TokenID::keyword_LOOSESCAN: - str->append(STRING_WITH_LEN("LOOSESCAN")); - break; - case TokenID::keyword_MATERIALIZATION: - str->append(STRING_WITH_LEN("MATERIALIZATION")); - break; - default: - DBUG_ASSERT(0); - } -} - -/* - Resolve a parsed subquery hint, i.e. set up proper Opt_hint_* structures - which will be used later during query preparation and optimization. - - Return value: - - false: no critical errors, warnings on duplicated hints, - unresolved query block names, etc. are allowed - - true: critical errors detected, break further hints processing -*/ -bool Parser::Subquery_hint::resolve(Parse_context *pc) const -{ - Opt_hints_qb *qb; - if (const At_query_block_name_subquery_strategy & - at_query_block_name_subquery_strategy= *this) - { - /* - This is @ query_block_name subquery_strategy, - e.g. SUBQUERY(@qb1 INTOEXISTS) - */ - const Lex_ident_sys qb_name= Query_block_name::to_ident_sys(pc->thd); - const Subquery_strategy &strat= at_query_block_name_subquery_strategy; - qb= resolve_for_qb_name(pc, strat.id(), &qb_name); - } - else - { - // This is subquery_strategy, e.g. SUBQUERY(MATERIALIZATION) - Lex_ident_sys empty_qb_name= Lex_ident_sys(); - const Hint_param_subquery_strategy &strat= *this; - qb= resolve_for_qb_name(pc, strat.id(), &empty_qb_name); - } - if (qb) - qb->subquery_hint= this; - return false; -} - - -/* - Helper function to be called by Subquery_hint::resolve(). - - Return value: - - pointer to Opt_hints_qb if the hint was resolved successfully - - NULL if the hint was ignored -*/ -Opt_hints_qb* Parser::Subquery_hint::resolve_for_qb_name(Parse_context *pc, - TokenID token_id, const Lex_ident_sys *qb_name) const -{ - Opt_hints_qb *qb= find_qb_hints(pc, *qb_name, SUBQUERY_HINT_ENUM, true); - if (!qb) - return nullptr; - if (qb->semijoin_hint) - { - print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, SUBQUERY_HINT_ENUM, - true, qb_name, nullptr, nullptr, this); - return nullptr; - } - if (qb->set_switch(true, SUBQUERY_HINT_ENUM, false)) - { - print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, SUBQUERY_HINT_ENUM, - true, qb_name, nullptr, nullptr, this); - return nullptr; - } - set_subquery_strategy(token_id, qb); - return qb; -} - - -void Parser::Subquery_hint::set_subquery_strategy(TokenID token_id, - Opt_hints_qb *qb) const -{ - switch(token_id) - { - case TokenID::keyword_INTOEXISTS: - qb->subquery_strategy= SUBS_IN_TO_EXISTS; - break; - case TokenID::keyword_MATERIALIZATION: - qb->subquery_strategy= SUBS_MATERIALIZATION; - break; - default: - DBUG_ASSERT(0); - } -} - - -void Parser::Subquery_hint::append_args(THD *thd, String *str) const -{ - TokenID token_id; - if (const At_query_block_name_subquery_strategy & - at_query_block_name_subquery_strategy= *this) - { - const Subquery_strategy &strat= at_query_block_name_subquery_strategy; - token_id= strat.id(); - } - else - { - const Hint_param_subquery_strategy& hint_param_strat= *this; - token_id= hint_param_strat.id(); - } - - switch(token_id) - { - case TokenID::keyword_INTOEXISTS: - str->append(STRING_WITH_LEN("INTOEXISTS")); - break; - case TokenID::keyword_MATERIALIZATION: - str->append(STRING_WITH_LEN("MATERIALIZATION")); - break; - default: - DBUG_ASSERT(0); - } -} - - -/* - This is the first step of MAX_EXECUTION_TIME() hint resolution. It is invoked - during the parsing phase, but at this stage some essential information is - not yet available, preventing a full validation of the hint. - Particularly, the type of SQL command, mark of a stored procedure execution - or whether SELECT_LEX is not top-level (i.e., a subquery) are not yet set. - However, some basic checks like the numeric argument validation or hint - duplication check can still be performed. - The second step of hint validation is performed during the JOIN preparation - phase, within Opt_hints_global::resolve(). By this point, all necessary - information is up-to-date, allowing the hint to be fully resolved -*/ -bool Parser::Max_execution_time_hint::resolve(Parse_context *pc) const -{ - const Unsigned_Number& hint_arg= *this; - const ULonglong_null time_ms= hint_arg.get_ulonglong(); - - if (time_ms.is_null() || time_ms.value() == 0 || time_ms.value() > INT_MAX32) - { - print_warn(pc->thd, ER_BAD_OPTION_VALUE, MAX_EXEC_TIME_HINT_ENUM, - true, NULL, NULL, NULL, this); - return false; - } - - Opt_hints_global *global_hint= get_global_hints(pc); - if (global_hint->is_specified(MAX_EXEC_TIME_HINT_ENUM)) - { - // Hint duplication: /*+ MAX_EXECUTION_TIME ... MAX_EXECUTION_TIME */ - print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, MAX_EXEC_TIME_HINT_ENUM, true, - NULL, NULL, NULL, this); - return false; - } - - global_hint->set_switch(true, MAX_EXEC_TIME_HINT_ENUM, false); - global_hint->max_exec_time_hint= this; - global_hint->max_exec_time_select_lex= pc->select; - return false; -} - - -void Parser::Max_execution_time_hint::append_args(THD *thd, String *str) const -{ - const Unsigned_Number& hint_arg= *this; - str->append(ErrConvString(hint_arg.str, hint_arg.length, - &my_charset_latin1).lex_cstring()); -} - - -ulonglong Parser::Max_execution_time_hint::get_milliseconds() const -{ - const Unsigned_Number& hint_arg= *this; - return hint_arg.get_ulonglong().value(); + String tbl_name_str, hint_type_str; + hint_type_str.append(opt_hint_info[type].hint_type); + append_table_name(thd, &tbl_name_str, tbl_name.table_name, tbl_name.qb_name); + uint err_code= ER_UNRESOLVED_TABLE_HINT_NAME; + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + err_code, ER_THD(thd, err_code), + tbl_name_str.c_ptr_safe(), hint_type_str.c_ptr_safe()); } @@ -1179,58 +990,3 @@ const char *dbug_print_hints(Opt_hints_qb *hint) return "Couldn't fit into buffer"; } #endif - - -bool Parser::Hint_list::resolve(Parse_context *pc) const -{ - if (pc->thd->lex->create_view) - { - // we're creating or modifying a view, hints are not allowed here - push_warning_printf(pc->thd, Sql_condition::WARN_LEVEL_WARN, - ER_HINTS_INSIDE_VIEWS_NOT_SUPPORTED, - ER_THD(pc->thd, ER_HINTS_INSIDE_VIEWS_NOT_SUPPORTED)); - return false; - } - - if (!get_qb_hints(pc)) - return true; - - for (Hint_list::iterator li= this->begin(); li != this->end(); ++li) - { - const Optimizer_hint_parser::Hint &hint= *li; - if (const Table_level_hint &table_hint= hint) - { - if (table_hint.resolve(pc)) - return true; - } - else if (const Index_level_hint &index_hint= hint) - { - if (index_hint.resolve(pc)) - return true; - } - else if (const Qb_name_hint &qb_hint= hint) - { - if (qb_hint.resolve(pc)) - return true; - } - else if (const Max_execution_time_hint &max_hint= hint) - { - if (max_hint.resolve(pc)) - return true; - } - else if (const Semijoin_hint &sj_hint= hint) - { - if (sj_hint.resolve(pc)) - return true; - } - else if (const Subquery_hint &subq_hint= hint) - { - if (subq_hint.resolve(pc)) - return true; - } - else { - DBUG_ASSERT(0); - } - } - return false; -} diff --git a/sql/opt_hints.h b/sql/opt_hints.h index d998da0d1a6..817a5a27ae2 100644 --- a/sql/opt_hints.h +++ b/sql/opt_hints.h @@ -39,6 +39,8 @@ Currently, this process is done at the parser stage. (This is one of the causes why hints do not work across VIEW bounds, here or in MySQL). + Query-block level hints can be reached through SELECT_LEX::opt_hints_qb. + == Hint "fixing" == During Name Resolution, hints are attached the real objects they control: @@ -64,10 +66,17 @@ == API for checking hints == - The optimizer checks hints' instructions using these calls: + The optimizer checks hints' instructions using these calls for table/index + level hints: hint_table_state() hint_table_state_or_fallback() hint_key_state() + For query block-level hints: + opt_hints_qb->semijoin_enabled() + opt_hints_qb->sj_enabled_strategies() + opt_hints_qb->apply_join_order_hints(join) - This adds extra dependencies + between tables that ensure that the optimizer picks a join order + prescribed by the hints. */ @@ -90,32 +99,15 @@ struct LEX; struct TABLE; -/** - Hint types, MAX_HINT_ENUM should be always last. - This enum should be synchronized with opt_hint_info - array(see opt_hints.cc). -*/ -enum opt_hints_enum -{ - BKA_HINT_ENUM= 0, - BNL_HINT_ENUM, - ICP_HINT_ENUM, - MRR_HINT_ENUM, - NO_RANGE_HINT_ENUM, - QB_NAME_HINT_ENUM, - MAX_EXEC_TIME_HINT_ENUM, - SEMIJOIN_HINT_ENUM, - SUBQUERY_HINT_ENUM, - MAX_HINT_ENUM // This one must be the last in the list -}; - - struct st_opt_hint_info { LEX_CSTRING hint_type; // Hint "type", like "BKA" or "MRR". bool check_upper_lvl; // true if upper level hint check is needed (for hints // which can be specified on more than one level). bool has_arguments; // true if hint has additional arguments. + bool irregular_hint; // true if hint requires some special handling. + // Currently it's used only for join order hints + // since they need a special printing procedure. }; typedef Optimizer_hint_parser Parser; @@ -137,24 +129,11 @@ public: hints_specified.clear_all(); } - /** - Check if hint is specified. - - @param type_arg hint type - - @return true if hint is specified, - false otherwise - */ my_bool is_specified(opt_hints_enum type_arg) const { return hints_specified.is_set(type_arg); } - /** - Set switch value and set hint into specified state. - @param type_arg hint type - @param switch_state_arg switch value - */ void set_switch(opt_hints_enum type_arg, bool switch_state_arg) { @@ -164,13 +143,7 @@ public: hints.clear_bit(type_arg); hints_specified.set_bit(type_arg); } - /** - Get switch value. - @param type_arg hint type - - @return switch value. - */ bool is_switched_on(opt_hints_enum type_arg) const { return hints.is_set(type_arg); @@ -364,6 +337,15 @@ protected: DBUG_ASSERT(0); return 0; } + + /** + Function prints hints which are non-standard and don't + fit into existing hint infrastructure. + + @param thd pointer to THD object + @param str pointer to String object + */ + virtual void print_irregular_hints(THD *thd, String *str) {} }; @@ -416,6 +398,10 @@ class Opt_hints_table; present after that) - [NO_]SEMIJOIN - SUBQUERY + - JOIN_PREFIX + - JOIN_SUFFIX + - JOIN_ORDER + - JOIN_FIXED_ORDER */ class Opt_hints_qb : public Opt_hints @@ -424,6 +410,14 @@ class Opt_hints_qb : public Opt_hints LEX_CSTRING sys_name; // System QB name char buff[32]; // Buffer to hold sys name + // Array of join order hints + Mem_root_array join_order_hints; + // Bitmap marking ignored hints + ulonglong join_order_hints_ignored; + // Max capacity to avoid overflowing of join_order_hints_ignored bitmap + static const uint MAX_ALLOWED_JOIN_ORDER_HINTS= + sizeof(join_order_hints_ignored) * 8; + public: Opt_hints_qb(Opt_hints *opt_hints_arg, MEM_ROOT *mem_root_arg, @@ -454,15 +448,7 @@ public: } void append_hint_arguments(THD *thd, opt_hints_enum hint, - String *str) override - { - if (hint == SUBQUERY_HINT_ENUM) - subquery_hint->append_args(thd, str); - else if (hint == SEMIJOIN_HINT_ENUM) - semijoin_hint->append_args(thd, str); - else - DBUG_ASSERT(0); - } + String *str) override; /** Function finds Opt_hints_table object corresponding to @@ -478,6 +464,14 @@ public: Opt_hints_table *fix_hints_for_table(TABLE *table, const Lex_ident_table &alias); + /** + Checks if join order hints are applicable and + applies table dependencies if possible. + + @param join JOIN object + */ + void apply_join_order_hints(JOIN *join); + /** Returns whether semi-join is enabled for this query block @@ -507,7 +501,7 @@ public: const Parser::Semijoin_hint* semijoin_hint= nullptr; - /* + /** Bitmap of strategies listed in the SEMIJOIN/NO_SEMIJOIN hint body, e.g. FIRSTMATCH | LOOSESCAN */ @@ -516,6 +510,32 @@ public: const Parser::Subquery_hint *subquery_hint= nullptr; uint subquery_strategy= SUBS_NOT_TRANSFORMED; + /** + Returns TRUE if the query block has at least one of the hints + JOIN_PREFIX(), JOIN_SUFFIX(), JOIN_ORDER() (but not JOIN_FIXED_ORDER()!) + */ + bool has_join_order_hints() const + { + return join_order_hints.size() > 0; + } + + /* + Adds a join order hint to the array if the capacity is not exceeded. + Returns FALSE on success, + TRUE on failure (capacity exceeded) + */ + bool add_join_order_hint(Parser::Join_order_hint *hint_arg) + { + if (join_order_hints.size() >= MAX_ALLOWED_JOIN_ORDER_HINTS) + return true; + join_order_hints.push_back(hint_arg); + return false; + } + + const Parser::Join_order_hint *join_prefix= nullptr; + const Parser::Join_order_hint *join_suffix= nullptr; + const Parser::Join_order_hint *join_fixed_order= nullptr; + void trace_hints(THD *thd) { if (unlikely(thd->trace_started())) @@ -528,6 +548,18 @@ public: obj.add("hints", str.c_ptr_safe()); } } + +private: + bool set_join_hint_deps(JOIN *join, const Parser::Join_order_hint *hint); + void update_nested_join_deps(JOIN *join, const JOIN_TAB *hint_tab, + table_map hint_tab_map); + table_map get_other_dep(JOIN *join, opt_hints_enum type, + table_map hint_tab_map, table_map table_map); + bool compare_table_name(const Parser::Table_name_and_Qb *hint_table_and_qb, + const TABLE_LIST *table); + void print_irregular_hints(THD *thd, String *str) override; + void print_join_order_warn(THD *thd, opt_hints_enum type, + const Parser::Table_name_and_Qb &tbl_name); }; diff --git a/sql/opt_hints_parser.cc b/sql/opt_hints_parser.cc index 31b0d08ac7c..55beaa1b378 100644 --- a/sql/opt_hints_parser.cc +++ b/sql/opt_hints_parser.cc @@ -16,16 +16,42 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ - #include "opt_hints_parser.h" #include "sql_error.h" #include "mysqld_error.h" #include "sql_class.h" #include "sql_show.h" +#include "opt_hints.h" +using Parser= Optimizer_hint_parser; extern struct st_opt_hint_info opt_hint_info[]; +// Forward declaration of functions +void print_warn(THD *thd, uint err_code, opt_hints_enum hint_type, + bool hint_state, + const Lex_ident_sys *qb_name_arg, + const Lex_ident_sys *table_name_arg, + const Lex_ident_sys *key_name_arg, + const Printable_parser_rule *hint); + +Opt_hints_qb *get_qb_hints(Parse_context *pc); + +Opt_hints_qb *find_qb_hints(Parse_context *pc, + const Lex_ident_sys &qb_name, + opt_hints_enum hint_type, + bool hint_state); + +Opt_hints_global *get_global_hints(Parse_context *pc); + +Opt_hints_table *get_table_hints(Parse_context *pc, + const Lex_ident_sys &table_name, + Opt_hints_qb *qb); + +void append_table_name(THD *thd, String *str, const LEX_CSTRING &table_name, + const LEX_CSTRING &qb_name); + +static const Lex_ident_sys null_ident_sys; Parse_context::Parse_context(THD *thd, st_select_lex *select) : thd(thd), @@ -74,6 +100,8 @@ Optimizer_hint_tokenizer::find_keyword(const LEX_CSTRING &str) return TokenID::keyword_FIRSTMATCH; else if ("INTOEXISTS"_Lex_ident_column.streq(str)) return TokenID::keyword_INTOEXISTS; + else if ("JOIN_ORDER"_Lex_ident_column.streq(str)) + return TokenID::keyword_JOIN_ORDER; break; case 11: @@ -81,6 +109,10 @@ Optimizer_hint_tokenizer::find_keyword(const LEX_CSTRING &str) return TokenID::keyword_NO_SEMIJOIN; else if ("DUPSWEEDOUT"_Lex_ident_column.streq(str)) return TokenID::keyword_DUPSWEEDOUT; + else if ("JOIN_PREFIX"_Lex_ident_column.streq(str)) + return TokenID::keyword_JOIN_PREFIX; + else if ("JOIN_SUFFIX"_Lex_ident_column.streq(str)) + return TokenID::keyword_JOIN_SUFFIX; break; case 15: @@ -88,6 +120,11 @@ Optimizer_hint_tokenizer::find_keyword(const LEX_CSTRING &str) return TokenID::keyword_MATERIALIZATION; break; + case 16: + if ("JOIN_FIXED_ORDER"_Lex_ident_column.streq(str)) + return TokenID::keyword_JOIN_FIXED_ORDER; + break; + case 18: if ("MAX_EXECUTION_TIME"_Lex_ident_column.streq(str)) return TokenID::keyword_MAX_EXECUTION_TIME; @@ -164,7 +201,7 @@ Optimizer_hint_tokenizer::get_token(CHARSET_INFO *cs) // This method is for debug purposes -bool Optimizer_hint_parser::parse_token_list(THD *thd) +bool Parser::parse_token_list(THD *thd) { for ( ; ; m_look_ahead_token= get_token(m_cs)) { @@ -182,8 +219,7 @@ bool Optimizer_hint_parser::parse_token_list(THD *thd) return true; // Success } -void Optimizer_hint_parser::push_warning_syntax_error(THD *thd, - uint start_lineno) +void Parser::push_warning_syntax_error(THD *thd, uint start_lineno) { DBUG_ASSERT(m_start <= m_ptr); DBUG_ASSERT(m_ptr <= m_end); @@ -202,9 +238,8 @@ void Optimizer_hint_parser::push_warning_syntax_error(THD *thd, bool -Optimizer_hint_parser:: - Table_name_list_container::add(Optimizer_hint_parser *p, - Table_name &&elem) +Parser::Table_name_list_container::add(Optimizer_hint_parser *p, + Table_name &&elem) { Table_name *pe= (Table_name*) p->m_thd->alloc(sizeof(*pe)); if (!pe) @@ -214,10 +249,8 @@ Optimizer_hint_parser:: } -bool -Optimizer_hint_parser:: - Hint_param_table_list_container::add(Optimizer_hint_parser *p, - Hint_param_table &&elem) +bool Parser::Hint_param_table_list_container::add(Optimizer_hint_parser *p, + Hint_param_table &&elem) { Hint_param_table *pe= (Hint_param_table*) p->m_thd->alloc(sizeof(*pe)); if (!pe) @@ -227,10 +260,8 @@ Optimizer_hint_parser:: } -bool -Optimizer_hint_parser:: - Hint_param_index_list_container::add(Optimizer_hint_parser *p, - Hint_param_index &&elem) +bool Parser::Hint_param_index_list_container::add(Optimizer_hint_parser *p, + Hint_param_index &&elem) { Hint_param_index *pe= (Hint_param_index*) p->m_thd->alloc(sizeof(*pe)); if (!pe) @@ -240,10 +271,7 @@ Optimizer_hint_parser:: } -bool -Optimizer_hint_parser:: - Hint_list_container::add(Optimizer_hint_parser *p, - Hint &&elem) +bool Parser::Hint_list_container::add(Optimizer_hint_parser *p, Hint &&elem) { Hint *pe= new (p->m_thd->mem_root) Hint; if (!pe) @@ -253,10 +281,8 @@ Optimizer_hint_parser:: } -bool -Optimizer_hint_parser:: - Semijoin_strategy_list_container::add(Optimizer_hint_parser *p, - Semijoin_strategy &&elem) +bool Parser::Semijoin_strategy_list_container::add(Optimizer_hint_parser *p, + Semijoin_strategy &&elem) { Semijoin_strategy *pe= (Semijoin_strategy*) p->m_thd->alloc(sizeof(*pe)); if (!pe) @@ -264,3 +290,774 @@ Optimizer_hint_parser:: *pe= std::move(elem); return push_back(pe, p->m_thd->mem_root); } + + +/* + Resolve a parsed table level hint, i.e. set up proper Opt_hint_* structures + which will be used later during query preparation and optimization. + +Return value: +- false: no critical errors, warnings on duplicated hints, + unresolved query block names, etc. are allowed +- true: critical errors detected, break further hints processing +*/ +bool Parser::Table_level_hint::resolve(Parse_context *pc) const +{ + const Table_level_hint_type &table_level_hint_type= *this; + opt_hints_enum hint_type; + bool hint_state; // ON or OFF + + switch (table_level_hint_type.id()) + { + case TokenID::keyword_BNL: + hint_type= BNL_HINT_ENUM; + hint_state= true; + break; + case TokenID::keyword_NO_BNL: + hint_type= BNL_HINT_ENUM; + hint_state= false; + break; + case TokenID::keyword_BKA: + hint_type= BKA_HINT_ENUM; + hint_state= true; + break; + case TokenID::keyword_NO_BKA: + hint_type= BKA_HINT_ENUM; + hint_state= false; + break; + default: + DBUG_ASSERT(0); + return true; + } + + if (const At_query_block_name_opt_table_name_list & + at_query_block_name_opt_table_name_list= *this) + { + // this is @ query_block_name opt_table_name_list + const Lex_ident_sys qb_name_sys= Query_block_name::to_ident_sys(pc->thd); + Opt_hints_qb *qb= find_qb_hints(pc, qb_name_sys, hint_type, hint_state); + if (qb == NULL) + return false; + if (at_query_block_name_opt_table_name_list.is_empty()) + { + // e.g. BKA(@qb1) + if (qb->set_switch(hint_state, hint_type, false)) + { + print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state, + &qb_name_sys, nullptr, nullptr, nullptr); + } + return false; + } + else + { + // e.g. BKA(@qb1 t1, t2, t3) + const Opt_table_name_list &opt_table_name_list= *this; + for (const Table_name &table : opt_table_name_list) + { + const Lex_ident_sys table_name_sys= table.to_ident_sys(pc->thd); + Opt_hints_table *tab= get_table_hints(pc, table_name_sys, qb); + if (!tab) + return false; + if (tab->set_switch(hint_state, hint_type, true)) + { + print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state, + &qb_name_sys, &table_name_sys, nullptr, + nullptr); + } + } + } + } + else + { + // this is opt_hint_param_table_list + const Opt_hint_param_table_list &opt_hint_param_table_list= *this; + Opt_hints_qb *qb= find_qb_hints(pc, Lex_ident_sys(), hint_type, hint_state); + if (qb == NULL) + return false; + if (opt_hint_param_table_list.is_empty()) + { + // e.g. BKA() + if (qb->set_switch(hint_state, hint_type, false)) + { + print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state, + &null_ident_sys, nullptr, nullptr, nullptr); + } + return false; + } + for (const Hint_param_table &table : opt_hint_param_table_list) + { + // e.g. BKA(t1@qb1, t2@qb2, t3) + const Lex_ident_sys qb_name_sys= table.Query_block_name:: + to_ident_sys(pc->thd); + Opt_hints_qb *qb= find_qb_hints(pc, qb_name_sys, hint_type, hint_state); + if (qb == NULL) + return false; + const Lex_ident_sys table_name_sys= table.Table_name:: + to_ident_sys(pc->thd); + Opt_hints_table *tab= get_table_hints(pc, table_name_sys, qb); + if (!tab) + return false; + if (tab->set_switch(hint_state, hint_type, true)) + { + print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state, + &qb_name_sys, &table_name_sys, nullptr, nullptr); + } + } + } + return false; +} + +/* + Resolve a parsed index level hint, i.e. set up proper Opt_hint_* structures + which will be used later during query preparation and optimization. + +Return value: +- false: no critical errors, warnings on duplicated hints, + unresolved query block names, etc. are allowed +- true: critical errors detected, break further hints processing +*/ +bool Parser::Index_level_hint::resolve(Parse_context *pc) const +{ + const Index_level_hint_type &index_level_hint_type= *this; + opt_hints_enum hint_type; + bool hint_state; // ON or OFF + + switch (index_level_hint_type.id()) + { + case TokenID::keyword_NO_ICP: + hint_type= ICP_HINT_ENUM; + hint_state= false; + break; + case TokenID::keyword_MRR: + hint_type= MRR_HINT_ENUM; + hint_state= true; + break; + case TokenID::keyword_NO_MRR: + hint_type= MRR_HINT_ENUM; + hint_state= false; + break; + case TokenID::keyword_NO_RANGE_OPTIMIZATION: + hint_type= NO_RANGE_HINT_ENUM; + hint_state= true; + break; + default: + DBUG_ASSERT(0); + return true; + } + + const Hint_param_table_ext &table_ext= *this; + const Lex_ident_sys qb_name_sys= table_ext.Query_block_name:: + to_ident_sys(pc->thd); + const Lex_ident_sys table_name_sys= table_ext.Table_name:: + to_ident_sys(pc->thd); + Opt_hints_qb *qb= find_qb_hints(pc, qb_name_sys, hint_type, hint_state); + if (qb == NULL) + return false; + + Opt_hints_table *tab= get_table_hints(pc, table_name_sys, qb); + if (!tab) + return false; + + if (is_empty()) // Table level hint + { + if (tab->set_switch(hint_state, hint_type, false)) + { + print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state, + &qb_name_sys, &table_name_sys, nullptr, nullptr); + } + return false; + } + + for (const Hint_param_index &index_name : *this) + { + const Lex_ident_sys index_name_sys= index_name.to_ident_sys(pc->thd); + Opt_hints_key *idx= (Opt_hints_key *)tab->find_by_name(index_name_sys); + if (!idx) + { + idx= new (pc->thd->mem_root) + Opt_hints_key(index_name_sys, tab, pc->thd->mem_root); + tab->register_child(idx); + } + + if (idx->set_switch(hint_state, hint_type, true)) + { + print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state, + &qb_name_sys, &table_name_sys, &index_name_sys, nullptr); + } + } + return false; +} + + +/* + Resolve a parsed query block name hint, i.e. set up proper Opt_hint_* + structures which will be used later during query preparation and optimization. + +Return value: +- false: no critical errors, warnings on duplicated hints, + unresolved query block names, etc. are allowed +- true: critical errors detected, break further hints processing +*/ +bool Parser::Qb_name_hint::resolve(Parse_context *pc) const +{ + Opt_hints_qb *qb= pc->select->opt_hints_qb; + + DBUG_ASSERT(qb); + + const Lex_ident_sys qb_name_sys= Query_block_name::to_ident_sys(pc->thd); + + if (qb->get_name().str || // QB name is already set + qb->get_parent()->find_by_name(qb_name_sys)) // Name is already used + { + print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, QB_NAME_HINT_ENUM, true, + &qb_name_sys, nullptr, nullptr, nullptr); + return false; + } + + qb->set_name(qb_name_sys); + return false; +} + + +void Parser::Semijoin_hint::fill_strategies_map(Opt_hints_qb *qb) const +{ + // Loop for hints like SEMIJOIN(firstmatch, dupsweedout) + const Hint_param_opt_sj_strategy_list &hint_param_strategy_list= *this; + for (const Semijoin_strategy &strat : hint_param_strategy_list) + add_strategy_to_map(strat.id(), qb); + + // Loop for hints like SEMIJOIN(@qb1 firstmatch, dupsweedout) + const Opt_sj_strategy_list &opt_sj_strategy_list= *this; + for (const Semijoin_strategy &strat : opt_sj_strategy_list) + add_strategy_to_map(strat.id(), qb); +} + + +void Parser::Semijoin_hint::add_strategy_to_map(TokenID token_id, + Opt_hints_qb *qb) const +{ + switch(token_id) + { + case TokenID::keyword_DUPSWEEDOUT: + qb->semijoin_strategies_map |= OPTIMIZER_SWITCH_DUPSWEEDOUT; + break; + case TokenID::keyword_FIRSTMATCH: + qb->semijoin_strategies_map |= OPTIMIZER_SWITCH_FIRSTMATCH; + break; + case TokenID::keyword_LOOSESCAN: + qb->semijoin_strategies_map |= OPTIMIZER_SWITCH_LOOSE_SCAN; + break; + case TokenID::keyword_MATERIALIZATION: + qb->semijoin_strategies_map |= OPTIMIZER_SWITCH_MATERIALIZATION; + break; + default: + DBUG_ASSERT(0); + } +} + +/* + Resolve a parsed semijoin hint, i.e. set up proper Opt_hint_* structures + which will be used later during query preparation and optimization. + +Return value: +- false: no critical errors, warnings on duplicated hints, + unresolved query block names, etc. are allowed +- true: critical errors detected, break further hints processing +*/ +bool Parser::Semijoin_hint::resolve(Parse_context *pc) const +{ + const Semijoin_hint_type &semijoin_hint_type= *this; + bool hint_state; // true - SEMIJOIN(), false - NO_SEMIJOIN() + if (semijoin_hint_type.id() == TokenID::keyword_SEMIJOIN) + hint_state= true; + else + hint_state= false; + Opt_hints_qb *qb; + if (const At_query_block_name_opt_strategy_list & + at_query_block_name_opt_strategy_list __attribute__((unused)) = *this) + { + /* + This is @ query_block_name opt_strategy_list, + e.g. SEMIJOIN(@qb1) or SEMIJOIN(@qb1 firstmatch, loosescan) + */ + const Lex_ident_sys qb_name= Query_block_name::to_ident_sys(pc->thd); + qb= resolve_for_qb_name(pc, hint_state, &qb_name); + } + else + { + // This is opt_strategy_list, e.g. SEMIJOIN(loosescan, dupsweedout) + Lex_ident_sys empty_qb_name= Lex_ident_sys(); + qb= resolve_for_qb_name(pc, hint_state, &empty_qb_name); + } + if (qb) + qb->semijoin_hint= this; + return false; +} + + +/* + Helper function to be called by Semijoin_hint::resolve(). + +Return value: +- pointer to Opt_hints_qb if the hint was resolved successfully +- NULL if the hint was ignored +*/ +Opt_hints_qb* Parser::Semijoin_hint:: + resolve_for_qb_name(Parse_context *pc, bool hint_state, + const Lex_ident_sys *qb_name) const +{ + Opt_hints_qb *qb= find_qb_hints(pc, *qb_name, SEMIJOIN_HINT_ENUM, hint_state); + if (!qb) + return nullptr; + if (qb->subquery_hint) + { + print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, SEMIJOIN_HINT_ENUM, + hint_state, qb_name, nullptr, nullptr, this); + return nullptr; + } + if (qb->set_switch(hint_state, SEMIJOIN_HINT_ENUM, false)) + { + print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, SEMIJOIN_HINT_ENUM, + hint_state, qb_name, nullptr, nullptr, this); + return nullptr; + } + fill_strategies_map(qb); + return qb; +} + + +void Parser::Semijoin_hint::append_args(THD *thd, String *str) const +{ + // Loop for hints without query block name, e.g. SEMIJOIN(firstmatch, dupsweedout) + const Hint_param_opt_sj_strategy_list &hint_param_strategy_list= *this; + uint32 len_before= str->length(); + for (const Semijoin_strategy &strat : hint_param_strategy_list) + { + if (str->length() > len_before) + str->append(STRING_WITH_LEN(", ")); + append_strategy_name(strat.id(), str); + } + + // Loop for hints with query block name, e.g. SEMIJOIN(@qb1 firstmatch, dupsweedout) + const Opt_sj_strategy_list &opt_sj_strategy_list= *this; + for (const Semijoin_strategy &strat : opt_sj_strategy_list) + { + if (str->length() > len_before) + str->append(STRING_WITH_LEN(", ")); + append_strategy_name(strat.id(), str); + } +} + + +void Parser::Semijoin_hint:: + append_strategy_name(TokenID token_id, String *str) const +{ + switch(token_id) + { + case TokenID::keyword_DUPSWEEDOUT: + str->append(STRING_WITH_LEN("DUPSWEEDOUT")); + break; + case TokenID::keyword_FIRSTMATCH: + str->append(STRING_WITH_LEN("FIRSTMATCH")); + break; + case TokenID::keyword_LOOSESCAN: + str->append(STRING_WITH_LEN("LOOSESCAN")); + break; + case TokenID::keyword_MATERIALIZATION: + str->append(STRING_WITH_LEN("MATERIALIZATION")); + break; + default: + DBUG_ASSERT(0); + } +} + +/* + Resolve a parsed subquery hint, i.e. set up proper Opt_hint_* structures + which will be used later during query preparation and optimization. + +Return value: +- false: no critical errors, warnings on duplicated hints, + unresolved query block names, etc. are allowed +- true: critical errors detected, break further hints processing +*/ +bool Parser::Subquery_hint::resolve(Parse_context *pc) const +{ + Opt_hints_qb *qb; + if (const At_query_block_name_subquery_strategy & + at_query_block_name_subquery_strategy= *this) + { + /* + This is @ query_block_name subquery_strategy, + e.g. SUBQUERY(@qb1 INTOEXISTS) + */ + const Lex_ident_sys qb_name= Query_block_name::to_ident_sys(pc->thd); + const Subquery_strategy &strat= at_query_block_name_subquery_strategy; + qb= resolve_for_qb_name(pc, strat.id(), &qb_name); + } + else + { + // This is subquery_strategy, e.g. SUBQUERY(MATERIALIZATION) + Lex_ident_sys empty_qb_name= Lex_ident_sys(); + const Hint_param_subquery_strategy &strat= *this; + qb= resolve_for_qb_name(pc, strat.id(), &empty_qb_name); + } + if (qb) + qb->subquery_hint= this; + return false; +} + + +/* + Helper function to be called by Subquery_hint::resolve(). + +Return value: +- pointer to Opt_hints_qb if the hint was resolved successfully +- NULL if the hint was ignored +*/ +Opt_hints_qb* Parser::Subquery_hint:: + resolve_for_qb_name(Parse_context *pc, TokenID token_id, + const Lex_ident_sys *qb_name) const +{ + Opt_hints_qb *qb= find_qb_hints(pc, *qb_name, SUBQUERY_HINT_ENUM, true); + if (!qb) + return nullptr; + if (qb->semijoin_hint) + { + print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, SUBQUERY_HINT_ENUM, + true, qb_name, nullptr, nullptr, this); + return nullptr; + } + if (qb->set_switch(true, SUBQUERY_HINT_ENUM, false)) + { + print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, SUBQUERY_HINT_ENUM, + true, qb_name, nullptr, nullptr, this); + return nullptr; + } + set_subquery_strategy(token_id, qb); + return qb; +} + + +void Parser::Subquery_hint::set_subquery_strategy(TokenID token_id, + Opt_hints_qb *qb) const +{ + switch(token_id) + { + case TokenID::keyword_INTOEXISTS: + qb->subquery_strategy= SUBS_IN_TO_EXISTS; + break; + case TokenID::keyword_MATERIALIZATION: + qb->subquery_strategy= SUBS_MATERIALIZATION; + break; + default: + DBUG_ASSERT(0); + } +} + + +void Parser::Subquery_hint::append_args(THD *thd, String *str) const +{ + TokenID token_id; + if (const At_query_block_name_subquery_strategy & + at_query_block_name_subquery_strategy= *this) + { + const Subquery_strategy &strat= at_query_block_name_subquery_strategy; + token_id= strat.id(); + } + else + { + const Hint_param_subquery_strategy& hint_param_strat= *this; + token_id= hint_param_strat.id(); + } + + switch(token_id) + { + case TokenID::keyword_INTOEXISTS: + str->append(STRING_WITH_LEN("INTOEXISTS")); + break; + case TokenID::keyword_MATERIALIZATION: + str->append(STRING_WITH_LEN("MATERIALIZATION")); + break; + default: + DBUG_ASSERT(0); + } +} + +/* + This is the first step of MAX_EXECUTION_TIME() hint resolution. It is invoked + during the parsing phase, but at this stage some essential information is + not yet available, preventing a full validation of the hint. + Particularly, the type of SQL command, mark of a stored procedure execution + or whether SELECT_LEX is not top-level (i.e., a subquery) are not yet set. + However, some basic checks like the numeric argument validation or hint + duplication check can still be performed. + The second step of hint validation is performed during the JOIN preparation + phase, within Opt_hints_global::resolve(). By this point, all necessary + information is up-to-date, allowing the hint to be fully resolved +*/ +bool Parser::Max_execution_time_hint::resolve(Parse_context *pc) const +{ + const Unsigned_Number& hint_arg= *this; + const ULonglong_null time_ms= hint_arg.get_ulonglong(); + + if (time_ms.is_null() || time_ms.value() == 0 || time_ms.value() > INT_MAX32) + { + print_warn(pc->thd, ER_BAD_OPTION_VALUE, MAX_EXEC_TIME_HINT_ENUM, + true, NULL, NULL, NULL, this); + return false; + } + + Opt_hints_global *global_hint= get_global_hints(pc); + if (global_hint->is_specified(MAX_EXEC_TIME_HINT_ENUM)) + { + // Hint duplication: /*+ MAX_EXECUTION_TIME ... MAX_EXECUTION_TIME */ + print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, MAX_EXEC_TIME_HINT_ENUM, true, + NULL, NULL, NULL, this); + return false; + } + + global_hint->set_switch(true, MAX_EXEC_TIME_HINT_ENUM, false); + global_hint->max_exec_time_hint= this; + global_hint->max_exec_time_select_lex= pc->select; + return false; +} + + +void Parser::Join_order_hint::append_args(THD *thd, String *str) const +{ + bool first_table_name= true; + for (const Parser::Table_name_and_Qb& tbl : table_names) + { + if (!first_table_name) + str->append(STRING_WITH_LEN(",")); + append_table_name(thd, str, tbl.table_name, tbl.qb_name); + first_table_name= false; + } +} + +/* + Resolve a parsed join order hint, i.e. set up proper Opt_hint_* structures + which will be used later during query preparation and optimization. + + Return value: + - false: no critical errors, warnings on duplicated hints, + unresolved query block names, etc. are allowed + - true: critical errors detected, break further hints processing +*/ +bool Parser::Join_order_hint::resolve(Parse_context *pc) +{ + const Join_order_hint_type &join_order_hint_type= *this; + + switch (join_order_hint_type.id()) + { + case TokenID::keyword_JOIN_FIXED_ORDER: + hint_type= JOIN_FIXED_ORDER_HINT_ENUM; + break; + case TokenID::keyword_JOIN_ORDER: + hint_type= JOIN_ORDER_HINT_ENUM; + break; + case TokenID::keyword_JOIN_PREFIX: + hint_type= JOIN_PREFIX_HINT_ENUM; + break; + case TokenID::keyword_JOIN_SUFFIX: + hint_type= JOIN_SUFFIX_HINT_ENUM; + break; + default: + DBUG_ASSERT(0); + return true; + } + + Opt_hints_qb *qb= nullptr; + Lex_ident_sys qb_name; + if (const At_query_block_name_opt_table_name_list &at_qb_tab_list= *this) + { + // this is @ query_block_name opt_table_name_list + qb_name= Query_block_name::to_ident_sys(pc->thd); + qb= find_qb_hints(pc, qb_name, hint_type, true); + // Compose `tables_names` list for warnings and final hints resolving + const Opt_table_name_list &opt_table_name_list= at_qb_tab_list; + for (const Table_name &table : opt_table_name_list) + { + Parser::Table_name_and_Qb *tbl_qb= new (pc->mem_root) + Parser::Table_name_and_Qb(table.to_ident_sys(pc->thd), Lex_ident_sys()); + if (!tbl_qb) + return true; + table_names.push_back(tbl_qb, pc->mem_root); + } + } + else + { + // this is opt_hint_param_table_list, query block name is not specified + qb= find_qb_hints(pc, Lex_ident_sys(), hint_type, true); + const Opt_hint_param_table_list &opt_hint_param_table_list= *this; + for (const Hint_param_table &table : opt_hint_param_table_list) + { + // e.g. JOIN_ORDER(t1@qb1, t2@qb2, t3) + Parser::Table_name_and_Qb *tbl_qb= + new (pc->mem_root) Parser::Table_name_and_Qb( + table.Table_name::to_ident_sys(pc->thd), + table.Query_block_name::to_ident_sys(pc->thd)); + table_names.push_back(tbl_qb, pc->mem_root); + } + } + + if (qb == nullptr) + return false; + + if ((hint_type != JOIN_FIXED_ORDER_HINT_ENUM && table_names.is_empty()) || + (hint_type == JOIN_FIXED_ORDER_HINT_ENUM && !table_names.is_empty())) + { + /* + Skipping table name(s) only allowed and required for the + JOIN_FIXED_ORDER hint and is not allowed for other hint types + */ + print_warn(pc->thd, ER_WARN_MALFORMED_HINT, hint_type, true, + &qb_name, nullptr, nullptr, this); + return false; + } + + if (hint_type == JOIN_FIXED_ORDER_HINT_ENUM) + { + /* + This is JOIN_ORDER_FIXED() or JOIN_ORDER_FIXED(@qb1) + There can be only one JOIN_ORDER_FIXED hint in a query block, + other hints are not allowed in this case + */ + if (qb->has_join_order_hints()|| qb->join_fixed_order) + { + print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, true, + &qb_name, nullptr, nullptr, this); + return false; + } + qb->join_fixed_order= this; + qb->set_switch(true, hint_type, false); + pc->select->options |= SELECT_STRAIGHT_JOIN; + return false; + } + + // Finished with processing of JOIN_FIXED_ORDER() + DBUG_ASSERT(hint_type != JOIN_FIXED_ORDER_HINT_ENUM); + /* + Hints except JOIN_ORDER() must not duplicate. If there is JOIN_ORDER_FIXED() + already, then other hints are not allowed for this query block + */ + if ((qb->get_switch(hint_type) && hint_type != JOIN_ORDER_HINT_ENUM) || + qb->join_fixed_order) + { + print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, true, + &qb_name, nullptr, nullptr, this); + return false; + } + + switch(hint_type) + { + case JOIN_PREFIX_HINT_ENUM: + if (qb->join_prefix || qb->add_join_order_hint(this)) + { + print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, true, + &qb_name, nullptr, nullptr, this); + return false; + } + qb->join_prefix= this; + qb->set_switch(true, JOIN_PREFIX_HINT_ENUM, false); + break; + case JOIN_SUFFIX_HINT_ENUM: + if (qb->join_suffix || qb->add_join_order_hint(this)) + { + print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, true, + &qb_name, nullptr, nullptr, this); + return false; + } + qb->join_suffix= this; + qb->set_switch(true, JOIN_SUFFIX_HINT_ENUM, false); + break; + case JOIN_ORDER_HINT_ENUM: + // Multiple JOIN_ORDER() hints are allowed + if (qb->add_join_order_hint(this)) + { + print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, true, + &qb_name, nullptr, nullptr, this); + return false; + } + qb->set_switch(true, JOIN_ORDER_HINT_ENUM, false); + break; + default: + DBUG_ASSERT(0); + } + return false; +} + + +void Parser::Max_execution_time_hint::append_args(THD *thd, String *str) const +{ + const Unsigned_Number& hint_arg= *this; + str->append(ErrConvString(hint_arg.str, hint_arg.length, + &my_charset_latin1).lex_cstring()); +} + + +ulonglong Parser::Max_execution_time_hint::get_milliseconds() const +{ + const Unsigned_Number& hint_arg= *this; + return hint_arg.get_ulonglong().value(); +} + + +bool Parser::Hint_list::resolve(Parse_context *pc) const +{ + if (pc->thd->lex->create_view) + { + // we're creating or modifying a view, hints are not allowed here + push_warning(pc->thd, Sql_condition::WARN_LEVEL_WARN, + ER_HINTS_INSIDE_VIEWS_NOT_SUPPORTED, + ER_THD(pc->thd, ER_HINTS_INSIDE_VIEWS_NOT_SUPPORTED)); + return false; + } + + if (!get_qb_hints(pc)) + return true; + + for (Hint_list::iterator li= this->begin(); li != this->end(); ++li) + { + Parser::Hint &hint= *li; + if (const Table_level_hint &table_hint= hint) + { + if (table_hint.resolve(pc)) + return true; + } + else if (const Index_level_hint &index_hint= hint) + { + if (index_hint.resolve(pc)) + return true; + } + else if (const Qb_name_hint &qb_hint= hint) + { + if (qb_hint.resolve(pc)) + return true; + } + else if (const Max_execution_time_hint &max_hint= hint) + { + if (max_hint.resolve(pc)) + return true; + } + else if (const Semijoin_hint &sj_hint= hint) + { + if (sj_hint.resolve(pc)) + return true; + } + else if (const Subquery_hint &subq_hint= hint) + { + if (subq_hint.resolve(pc)) + return true; + } + else if (Join_order_hint &join_order_hint= hint) + { + if (join_order_hint.resolve(pc)) + return true; + } + else { + DBUG_ASSERT(0); + } + } + return false; +} diff --git a/sql/opt_hints_parser.h b/sql/opt_hints_parser.h index d50f52ef7eb..0a8e13f53cb 100644 --- a/sql/opt_hints_parser.h +++ b/sql/opt_hints_parser.h @@ -28,6 +28,29 @@ class st_select_lex; class Opt_hints_qb; +/** + Hint types, MAX_HINT_ENUM should be always last. + This enum should be synchronized with opt_hint_info + array(see opt_hints.cc). +*/ +enum opt_hints_enum +{ + BKA_HINT_ENUM= 0, + BNL_HINT_ENUM, + ICP_HINT_ENUM, + MRR_HINT_ENUM, + NO_RANGE_HINT_ENUM, + QB_NAME_HINT_ENUM, + MAX_EXEC_TIME_HINT_ENUM, + SEMIJOIN_HINT_ENUM, + SUBQUERY_HINT_ENUM, + JOIN_PREFIX_HINT_ENUM, + JOIN_SUFFIX_HINT_ENUM, + JOIN_ORDER_HINT_ENUM, + JOIN_FIXED_ORDER_HINT_ENUM, + MAX_HINT_ENUM // This one must be the last in the list +}; + /** Environment data for the name resolution phase */ @@ -63,9 +86,12 @@ public: tAT= '@', tLPAREN= '(', tRPAREN= ')', + // Other token types + tIDENT= 'i', + tUNSIGNED_NUMBER= 'n', // Keywords - keyword_BKA, + keyword_BKA = 256, // Value must be greater than any of the above keyword_BNL, keyword_NO_BKA, keyword_NO_BNL, @@ -83,10 +109,10 @@ public: keyword_LOOSESCAN, keyword_DUPSWEEDOUT, keyword_INTOEXISTS, - - // Other token types - tIDENT, - tUNSIGNED_NUMBER + keyword_JOIN_PREFIX, + keyword_JOIN_SUFFIX, + keyword_JOIN_ORDER, + keyword_JOIN_FIXED_ORDER }; class Token: public Lex_cstring @@ -818,6 +844,76 @@ public: }; + /* + join_order_hint_type ::= JOIN_FIXED_ORDER + | JOIN_ORDER + | JOIN_PREFIX + | JOIN_SUFFIX + */ + class Join_order_hint_type_cond + { + public: + static bool allowed_token_id(TokenID id) + { + return id == TokenID::keyword_JOIN_FIXED_ORDER || + id == TokenID::keyword_JOIN_ORDER || + id == TokenID::keyword_JOIN_PREFIX || + id == TokenID::keyword_JOIN_SUFFIX; + } + }; + class Join_order_hint_type: public TokenChoice + { + public: + using TokenChoice::TokenChoice; + }; + + /* + Struct representing table names listed in optimizer hints bodies. + They may optionally include query block names, for example: + t1, t2@qb1, t3, t4@qb5 + */ + struct Table_name_and_Qb: public Sql_alloc + { + Lex_ident_sys table_name; + Lex_ident_sys qb_name; // may be empty + + Table_name_and_Qb(const Lex_ident_sys& tbl, const Lex_ident_sys& qb) : + table_name(tbl), qb_name(qb) + {} + + Table_name_and_Qb(Lex_ident_sys&& tbl, Lex_ident_sys&& qb) : + table_name(std::move(tbl)), qb_name(std::move(qb)) + {} + }; + + /* + join_order_hint ::= join_order_hint_type ( table_level_hint_body ) + */ + class Join_order_hint: public AND4, + public Printable_parser_rule + { + public: + using AND4::AND4; + + opt_hints_enum hint_type= MAX_HINT_ENUM; + + bool resolve(Parse_context *pc); + + void append_args(THD *thd, String *str) const override; + + /* + Table names (optionally augmented with query block names) listed in + the hint body. + */ + List table_names; + }; + + /* hint ::= index_level_hint | table_level_hint @@ -825,17 +921,19 @@ public: | max_execution_time_hint | semijoin_hint | subquery_hint + | join_order_hint */ - class Hint: public OR6 + Subquery_hint, + Join_order_hint> { public: - using OR6::OR6; + using OR7::OR7; }; private: diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index f73ed37a0cb..248633c3eeb 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -12324,3 +12324,5 @@ ER_UNRESOLVED_INDEX_HINT_NAME eng "Unresolved index name %s for %s hint" ER_HINTS_INSIDE_VIEWS_NOT_SUPPORTED eng "Optimizer hints are not supported inside view definitions" +ER_WARN_MALFORMED_HINT + eng "Hint %s is ignored as malformed" diff --git a/sql/simple_parser.h b/sql/simple_parser.h index 69110130105..611b7e6a936 100644 --- a/sql/simple_parser.h +++ b/sql/simple_parser.h @@ -519,24 +519,27 @@ protected: }; /* - A rule consisting of a choice of six rules: - rule ::= rule1 | rule2 | rule3 | rule4 | rule5 | rule6 + A rule consisting of a choice of seven rules: + rule ::= rule1 | rule2 | rule3 | rule4 | rule5 | rule6 | rule7 */ - template - class OR6: public A, public B, public C, public D, public E, public F + template + class OR7: public A, public B, public C, public D, public E, public F, + public G { public: - OR6() + OR7() { } - OR6(OR6 &&rhs) + OR7(OR7 &&rhs) :A(std::move(static_cast(rhs))), B(std::move(static_cast(rhs))), C(std::move(static_cast(rhs))), D(std::move(static_cast(rhs))), E(std::move(static_cast(rhs))), - F(std::move(static_cast(rhs))) + F(std::move(static_cast(rhs))), + G(std::move(static_cast(rhs))) { } - OR6 & operator=(OR6 &&rhs) + OR7 & operator=(OR7 &&rhs) { A::operator=(std::move(static_cast(rhs))); B::operator=(std::move(static_cast(rhs))); @@ -544,9 +547,10 @@ protected: D::operator=(std::move(static_cast(rhs))); E::operator=(std::move(static_cast(rhs))); F::operator=(std::move(static_cast(rhs))); + G::operator=(std::move(static_cast(rhs))); return *this; } - OR6(PARSER *p) + OR7(PARSER *p) :A(p), B(A::operator bool() ? B() : B(p)), C(A::operator bool() || B::operator bool() ? C() : C(p)), @@ -555,14 +559,18 @@ protected: E(A::operator bool() || B::operator bool() || C::operator bool() || D::operator bool() ? E() : E(p)), F(A::operator bool() || B::operator bool() || C::operator bool() || - D::operator bool() || E::operator bool() ? F() : F(p)) + D::operator bool() || E::operator bool() ? F() : F(p)), + G(A::operator bool() || B::operator bool() || C::operator bool() || + D::operator bool() || E::operator bool() || F::operator bool() ? + G() : G(p)) { DBUG_ASSERT(!operator bool() || !p->is_error()); } operator bool() const { return A::operator bool() || B::operator bool() || C::operator bool() || - D::operator bool() || E::operator bool() || F::operator bool(); + D::operator bool() || E::operator bool() || F::operator bool() || + G::operator bool(); } }; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 97b05bc3223..870c05cc681 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -5765,54 +5765,12 @@ make_join_statistics(JOIN *join, List &tables_list, stat_vector[i]=0; join->outer_join=outer_join; - if (join->outer_join) + if (join->propagate_dependencies(stat)) { - /* - Build transitive closure for relation 'to be dependent on'. - This will speed up the plan search for many cases with outer joins, - as well as allow us to catch illegal cross references/ - Warshall's algorithm is used to build the transitive closure. - As we use bitmaps to represent the relation the complexity - of the algorithm is O((number of tables)^2). - - The classic form of the Warshall's algorithm would look like: - for (i= 0; i < table_count; i++) - { - for (j= 0; j < table_count; j++) - { - for (k= 0; k < table_count; k++) - { - if (bitmap_is_set(stat[j].dependent, i) && - bitmap_is_set(stat[i].dependent, k)) - bitmap_set_bit(stat[j].dependent, k); - } - } - } - */ - - for (s= stat ; s < stat_end ; s++) - { - TABLE *table= s->table; - for (JOIN_TAB *t= stat ; t < stat_end ; t++) - { - if (t->dependent & table->map) - t->dependent |= table->reginfo.join_tab->dependent; - } - if (outer_join & s->table->map) - s->table->maybe_null= 1; - } - /* Catch illegal cross references for outer joins */ - for (i= 0, s= stat ; i < table_count ; i++, s++) - { - if (s->dependent & s->table->map) - { - join->table_count=0; // Don't use join->table - my_message(ER_WRONG_OUTER_JOIN, - ER_THD(join->thd, ER_WRONG_OUTER_JOIN), MYF(0)); - goto error; - } - s->key_dependent= s->dependent; - } + // Illegal cross-references found + table_count= 0; + my_message(ER_WRONG_OUTER_JOIN, ER_THD(thd, ER_WRONG_OUTER_JOIN), MYF(0)); + goto error; } { @@ -5826,9 +5784,6 @@ make_join_statistics(JOIN *join, List &tables_list, } } - if (unlikely(thd->trace_started())) - trace_table_dependencies(thd, stat, join->table_count); - if (join->conds || outer_join) { if (update_ref_and_keys(thd, keyuse_array, stat, join->table_count, @@ -6320,6 +6275,13 @@ make_join_statistics(JOIN *join, List &tables_list, join->const_tables=const_count; join->found_const_table_map=found_const_table_map; + if (join->select_lex->opt_hints_qb) + join->select_lex->opt_hints_qb->apply_join_order_hints(join); + join->update_key_dependencies(); + + if (unlikely(thd->trace_started())) + trace_table_dependencies(thd, join->join_tab, join->table_count); + if (sj_nests) join->select_lex->update_available_semijoin_strategies(thd); @@ -6413,6 +6375,102 @@ error: } +/* + Propagate dependencies between tables. + + @returns false if success, true if error + + Build transitive closure for relation 'to be dependent on'. + This will speed up the plan search for many cases with outer joins, + as well as allow us to catch illegal cross references/ + Warshall's algorithm is used to build the transitive closure. + As we use bitmaps to represent the relation the complexity + of the algorithm is O((number of tables)^2). + + The classic form of the Warshall's algorithm would look like: + for (i= 0; i < table_count; i++) + { + for (j= 0; j < table_count; j++) + { + for (k= 0; k < table_count; k++) + { + if (bitmap_is_set(stat[j].dependent, i) && + bitmap_is_set(stat[i].dependent, k)) + bitmap_set_bit(stat[j].dependent, k); + } + } + } +*/ + +bool JOIN::propagate_dependencies(JOIN_TAB *stat) +{ + for (JOIN_TAB *s= stat; s < stat + table_count; s++) + { + TABLE *table= s->table; + if (outer_join & s->table->map) + s->table->maybe_null= 1; + + if (!table->reginfo.join_tab->dependent) + continue; + // Add my dependencies to other tables depending on me + for (JOIN_TAB *t= stat; t < stat + table_count; t++) + { + if (t->dependent & table->map) + t->dependent |= table->reginfo.join_tab->dependent; + } + } + // Catch illegal cross references + for (JOIN_TAB *s= stat; s < stat + table_count; s++) + { + if (s->dependent & s->table->map) + return true; + } + return false; +} + + +void JOIN::update_key_dependencies() +{ + for (JOIN_TAB *tab= join_tab; tab < join_tab + table_count; tab++) + tab->key_dependent |= tab->dependent; +} + + +/* + Export dependencies of the JOIN tables to a newly allocated array of bitmaps + (table_map's). + This array may be used to restore the original dependencies + (see restore_table_dependencies()) +*/ + +table_map *JOIN::export_table_dependencies() const +{ + table_map *orig_dep_array= + (table_map *)thd->alloc(sizeof(table_map) * table_count); + + if (orig_dep_array == nullptr) + return nullptr; + + for (uint i= 0; i < table_count; i++) + orig_dep_array[i]= join_tab[i].dependent; + + return orig_dep_array; +} + + +/* + Restore dependencies of the JOIN tables from a previously exported array + of bitmaps (table_map's) (see export_table_dependencies()). + This function overwrites the existing dependencies with those from the array. +*/ + +void JOIN::restore_table_dependencies(table_map *orig_dep_array) +{ + for (uint i = 0; i < table_count; i++) + join_tab[i].dependent= orig_dep_array[i]; +} + + /***************************************************************************** Check with keys are used and with tables references with tables Updates in stat: @@ -11476,12 +11534,17 @@ get_costs_for_tables(JOIN *join, table_map remaining_tables, uint idx, bool found_eq_ref= 0; DBUG_ENTER("get_plans_for_tables"); + table_map remaining_allowed_tables= + (join->emb_sjm_nest ? + (join->emb_sjm_nest->sj_inner_tables & + ~join->const_table_map & remaining_tables): + remaining_tables); s= *pos; do { table_map real_table_bit= s->table->map; if ((*allowed_tables & real_table_bit) && - !(remaining_tables & s->dependent)) + !(remaining_allowed_tables & s->dependent)) { #ifdef DBUG_ASSERT_EXISTS DBUG_ASSERT(!check_interleaving_with_nj(s)); @@ -15723,15 +15786,15 @@ uint check_join_cache_usage(JOIN_TAB *tab, !(join->allowed_join_cache_types & JOIN_CACHE_INCREMENTAL_BIT); bool no_hashed_cache= !(join->allowed_join_cache_types & JOIN_CACHE_HASHED_BIT); - bool no_bnl_cache= !hint_table_state(join->thd, tab->tab_list->table, - BNL_HINT_ENUM, true); + bool hint_disables_bnl= !hint_table_state(join->thd, tab->tab_list->table, + BNL_HINT_ENUM, true); bool no_bka_cache= !hint_table_state(join->thd, tab->tab_list->table, BKA_HINT_ENUM, join->allowed_join_cache_types & JOIN_CACHE_BKA_BIT); bool hint_forces_bka= hint_table_state(join->thd, tab->tab_list->table, BKA_HINT_ENUM, false); join->return_tab= 0; - if (tab->no_forced_join_cache || (no_bnl_cache && no_bka_cache)) + if (tab->no_forced_join_cache || (hint_disables_bnl && no_bka_cache)) goto no_join_cache; if (cache_level < 4 && hint_table_state(join->thd, tab->tab_list->table, @@ -15875,7 +15938,7 @@ uint check_join_cache_usage(JOIN_TAB *tab, case JT_NEXT: case JT_ALL: case JT_RANGE: - if (no_bnl_cache) + if (hint_disables_bnl) goto no_join_cache; if (cache_level == 1) prev_cache= 0; @@ -15915,7 +15978,7 @@ uint check_join_cache_usage(JOIN_TAB *tab, tab->is_ref_for_hash_join() || ((flags & HA_MRR_NO_ASSOCIATION) && cache_level <=6)) { - if (no_bnl_cache) + if (hint_disables_bnl) goto no_join_cache; if (!tab->hash_join_is_possible() || tab->make_scan_filter()) @@ -32457,6 +32520,15 @@ void JOIN::set_allowed_join_cache_types() bool JOIN::is_allowed_hash_join_access(const TABLE *table) { + /* + If both NO_BNL() and NO_BKA() hints are specified then + hash join is not allowed + */ + if (!hint_table_state(thd, table, BNL_HINT_ENUM, true) && + !hint_table_state(thd, table, BKA_HINT_ENUM, true)) + { + return false; + } return allowed_join_cache_types & JOIN_CACHE_HASHED_BIT && (max_allowed_join_cache_level > JOIN_CACHE_HASHED_BIT || hint_table_state(thd, table, BNL_HINT_ENUM, false) || diff --git a/sql/sql_select.h b/sql/sql_select.h index 0a9fb36727d..08e9214a8db 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -378,8 +378,9 @@ typedef struct st_join_table { */ table_map dependent; /* - key_dependent is dependent but add those tables that are used to compare - with a key field in a simple expression. See add_key_field(). + Normally `key_dependent` is the same as `dependent` but may also include + tables that are used to compare with a key field in a simple expression + (see add_key_field()). It is only used to prune searches in best_extension_by_limited_search() */ table_map key_dependent; @@ -1955,6 +1956,10 @@ public: bool optimize_upper_rownum_func(); void calc_allowed_top_level_tables(SELECT_LEX *lex); table_map get_allowed_nj_tables(uint idx); + bool propagate_dependencies(JOIN_TAB *stat); + void update_key_dependencies(); + table_map *export_table_dependencies() const; + void restore_table_dependencies(table_map *orig_dep_array); private: /**