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.
This commit is contained in:
parent
c4fe794d22
commit
349f5bf2da
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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 <cache>(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;
|
||||
|
1326
mysql-test/main/opt_hints_join_order.result
Normal file
1326
mysql-test/main/opt_hints_join_order.result
Normal file
File diff suppressed because it is too large
Load Diff
791
mysql-test/main/opt_hints_join_order.test
Normal file
791
mysql-test/main/opt_hints_join_order.test
Normal file
@ -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;
|
@ -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 <derived2> 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 <expr_cache><`test`.`t2`.`a`>(<in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`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 <expr_cache><`test`.`t2`.`a`>(<in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`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 <expr_cache><`test`.`t2`.`a`>(<in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`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 <expr_cache><`test`.`t1`.`a`>(<in_optimizer>(`test`.`t1`.`a`,<exists>(<index_lookup>(<cache>(`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 <expr_cache><`test`.`t2`.`a`>(<in_optimizer>(`test`.`t2`.`a`,`test`.`t2`.`a` in ( <materialize> (/* select#2 */ select `test`.`t1`.`a` from `test`.`t1` ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on distinct_key where `test`.`t2`.`a` = `<subquery2>`.`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 <expr_cache><`test`.`t2`.`a`>(<in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`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 <expr_cache><`test`.`t2`.`a`>(<in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`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 <expr_cache><`test`.`t2`.`a`>(<in_optimizer>(`test`.`t2`.`a`,`test`.`t2`.`a` in ( <materialize> (/* select#2 */ select /*+ QB_NAME(`subq`) */ `test`.`t1`.`a` from `test`.`t1` ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on distinct_key where `test`.`t2`.`a` = `<subquery2>`.`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 <expr_cache><`test`.`t2`.`a`>(<in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`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 <expr_cache><`test`.`t2`.`a`>(<in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`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 <expr_cache><`test`.`t2`.`a`>(<in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`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 <expr_cache><`test`.`t2`.`a`>(<in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on PRIMARY))))
|
||||
DROP TABLE t1,t2,t3;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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": [
|
||||
{
|
||||
|
@ -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": [
|
||||
{
|
||||
|
@ -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": [
|
||||
{
|
||||
|
956
sql/opt_hints.cc
956
sql/opt_hints.cc
File diff suppressed because it is too large
Load Diff
132
sql/opt_hints.h
132
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<Parser::Join_order_hint *, false> 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);
|
||||
};
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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<Parser,
|
||||
Join_order_hint_type_cond>
|
||||
{
|
||||
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<Parser,
|
||||
Join_order_hint_type,
|
||||
LParen,
|
||||
Table_level_hint_body,
|
||||
RParen>,
|
||||
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_name_and_Qb> 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<Parser,
|
||||
class Hint: public OR7<Parser,
|
||||
Index_level_hint,
|
||||
Table_level_hint,
|
||||
Qb_name_hint,
|
||||
Max_execution_time_hint,
|
||||
Semijoin_hint,
|
||||
Subquery_hint>
|
||||
Subquery_hint,
|
||||
Join_order_hint>
|
||||
{
|
||||
public:
|
||||
using OR6::OR6;
|
||||
using OR7::OR7;
|
||||
};
|
||||
|
||||
private:
|
||||
|
@ -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"
|
||||
|
@ -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 PARSER, class A, class B, class C, class D, class E, class F>
|
||||
class OR6: public A, public B, public C, public D, public E, public F
|
||||
template<class PARSER, class A, class B, class C, class D, class E, class F,
|
||||
class G>
|
||||
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<A&&>(rhs))),
|
||||
B(std::move(static_cast<B&&>(rhs))),
|
||||
C(std::move(static_cast<C&&>(rhs))),
|
||||
D(std::move(static_cast<D&&>(rhs))),
|
||||
E(std::move(static_cast<E&&>(rhs))),
|
||||
F(std::move(static_cast<F&&>(rhs)))
|
||||
F(std::move(static_cast<F&&>(rhs))),
|
||||
G(std::move(static_cast<G&&>(rhs)))
|
||||
{ }
|
||||
OR6 & operator=(OR6 &&rhs)
|
||||
OR7 & operator=(OR7 &&rhs)
|
||||
{
|
||||
A::operator=(std::move(static_cast<A&&>(rhs)));
|
||||
B::operator=(std::move(static_cast<B&&>(rhs)));
|
||||
@ -544,9 +547,10 @@ protected:
|
||||
D::operator=(std::move(static_cast<D&&>(rhs)));
|
||||
E::operator=(std::move(static_cast<E&&>(rhs)));
|
||||
F::operator=(std::move(static_cast<F&&>(rhs)));
|
||||
G::operator=(std::move(static_cast<G&&>(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();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -5765,54 +5765,12 @@ make_join_statistics(JOIN *join, List<TABLE_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<TABLE_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<TABLE_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) ||
|
||||
|
@ -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:
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user