mirror of
https://github.com/MariaDB/server.git
synced 2025-08-07 00:04:31 +03:00
MDEV-34888 Implement SEMIJOIN() and SUBQUERY() hints
This commit is contained in:
@@ -8,7 +8,7 @@
|
|||||||
set @save_optimizer_switch=@@optimizer_switch;
|
set @save_optimizer_switch=@@optimizer_switch;
|
||||||
set @save_join_cache_level=@@join_cache_level;
|
set @save_join_cache_level=@@join_cache_level;
|
||||||
|
|
||||||
set optimizer_switch="index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on,rowid_filter=on,condition_pushdown_from_having=on";
|
set optimizer_switch="index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,duplicateweedout=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on,rowid_filter=on,condition_pushdown_from_having=on";
|
||||||
|
|
||||||
set optimizer_use_condition_selectivity=4;
|
set optimizer_use_condition_selectivity=4;
|
||||||
set optimizer_search_depth=62;
|
set optimizer_search_depth=62;
|
||||||
|
@@ -881,7 +881,7 @@ The following specify which files/extra groups are read (specified before remain
|
|||||||
index_merge_sort_union, index_merge_intersection,
|
index_merge_sort_union, index_merge_intersection,
|
||||||
index_merge_sort_intersection, index_condition_pushdown,
|
index_merge_sort_intersection, index_condition_pushdown,
|
||||||
derived_merge, derived_with_keys, firstmatch, loosescan,
|
derived_merge, derived_with_keys, firstmatch, loosescan,
|
||||||
materialization, in_to_exists, semijoin,
|
duplicateweedout, materialization, in_to_exists, semijoin,
|
||||||
partial_match_rowid_merge, partial_match_table_scan,
|
partial_match_rowid_merge, partial_match_table_scan,
|
||||||
subquery_cache, mrr, mrr_cost_based, mrr_sort_keys,
|
subquery_cache, mrr, mrr_cost_based, mrr_sort_keys,
|
||||||
outer_join_with_cache, semijoin_with_cache,
|
outer_join_with_cache, semijoin_with_cache,
|
||||||
@@ -1889,7 +1889,7 @@ optimizer-rowid-copy-cost 0.002653
|
|||||||
optimizer-scan-setup-cost 10
|
optimizer-scan-setup-cost 10
|
||||||
optimizer-search-depth 62
|
optimizer-search-depth 62
|
||||||
optimizer-selectivity-sampling-limit 100
|
optimizer-selectivity-sampling-limit 100
|
||||||
optimizer-switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on,rowid_filter=on,condition_pushdown_from_having=on,not_null_range_scan=off,hash_join_cardinality=on,cset_narrowing=on,sargable_casefold=on
|
optimizer-switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,duplicateweedout=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on,rowid_filter=on,condition_pushdown_from_having=on,not_null_range_scan=off,hash_join_cardinality=on,cset_narrowing=on,sargable_casefold=on
|
||||||
optimizer-trace
|
optimizer-trace
|
||||||
optimizer-trace-max-mem-size 1048576
|
optimizer-trace-max-mem-size 1048576
|
||||||
optimizer-use-condition-selectivity 4
|
optimizer-use-condition-selectivity 4
|
||||||
|
@@ -33,7 +33,7 @@ set @save_optimizer_switch=@@optimizer_switch;
|
|||||||
SET @@session.session_track_system_variables='optimizer_switch';
|
SET @@session.session_track_system_variables='optimizer_switch';
|
||||||
set optimizer_switch='index_merge=off,index_merge_union=off,index_merge_sort_union=off,index_merge_intersection=off,index_merge_sort_intersection=on,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=on,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=on,mrr_cost_based=on,mrr_sort_keys=on,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=on,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off';
|
set optimizer_switch='index_merge=off,index_merge_union=off,index_merge_sort_union=off,index_merge_intersection=off,index_merge_sort_intersection=on,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=on,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=on,mrr_cost_based=on,mrr_sort_keys=on,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=on,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off';
|
||||||
-- Tracker : SESSION_TRACK_SYSTEM_VARIABLES
|
-- Tracker : SESSION_TRACK_SYSTEM_VARIABLES
|
||||||
-- optimizer_switch: index_merge=off,index_merge_union=off,index_merge_sort_union=off,index_merge_intersection=off,index_merge_sort_intersection=on,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=on,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=on,mrr_cost_based=on,mrr_sort_keys=on,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=on,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=on,condition_pushdown_for_subquery=on,rowid_filter=on,condition_pushdown_from_having=on,not_null_range_scan=off,hash_join_cardinality=on,cset_narrowing=on,sargable_casefold=on
|
-- optimizer_switch: index_merge=off,index_merge_union=off,index_merge_sort_union=off,index_merge_intersection=off,index_merge_sort_intersection=on,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,duplicateweedout=on,materialization=on,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=on,mrr_cost_based=on,mrr_sort_keys=on,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=on,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=on,condition_pushdown_for_subquery=on,rowid_filter=on,condition_pushdown_from_having=on,not_null_range_scan=off,hash_join_cardinality=on,cset_narrowing=on,sargable_casefold=on
|
||||||
|
|
||||||
set @@optimizer_switch=@save_optimizer_switch;
|
set @@optimizer_switch=@save_optimizer_switch;
|
||||||
SET @@session.session_track_system_variables= @save_session_track_system_variables;
|
SET @@session.session_track_system_variables= @save_session_track_system_variables;
|
||||||
|
@@ -1,4 +1,6 @@
|
|||||||
|
--source include/not_embedded.inc
|
||||||
--source include/have_sequence.inc
|
--source include/have_sequence.inc
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # MAX_EXECUTION_TIME hint testing
|
--echo # MAX_EXECUTION_TIME hint testing
|
||||||
--echo #
|
--echo #
|
||||||
|
@@ -56,6 +56,7 @@ ANALYZE TABLE t3;
|
|||||||
set optimizer_switch=default;
|
set optimizer_switch=default;
|
||||||
|
|
||||||
--disable_ps2_protocol
|
--disable_ps2_protocol
|
||||||
|
--disable_cursor_protocol
|
||||||
--echo # Check statistics with no hint
|
--echo # Check statistics with no hint
|
||||||
FLUSH STATUS;
|
FLUSH STATUS;
|
||||||
SELECT f1 FROM t3 WHERE f1 > 30 AND f1 < 33;
|
SELECT f1 FROM t3 WHERE f1 > 30 AND f1 < 33;
|
||||||
@@ -66,6 +67,7 @@ FLUSH STATUS;
|
|||||||
SELECT /*+ NO_RANGE_OPTIMIZATION(t3 PRIMARY, f2_idx) */ f1 FROM t3 WHERE f1 > 30 AND f1 < 33;
|
SELECT /*+ NO_RANGE_OPTIMIZATION(t3 PRIMARY, f2_idx) */ f1 FROM t3 WHERE f1 > 30 AND f1 < 33;
|
||||||
SHOW STATUS LIKE 'handler_read%';
|
SHOW STATUS LIKE 'handler_read%';
|
||||||
--enable_ps2_protocol
|
--enable_ps2_protocol
|
||||||
|
--enable_cursor_protocol
|
||||||
|
|
||||||
EXPLAIN EXTENDED SELECT f1 FROM t3 WHERE f1 > 30 AND f1 < 33;
|
EXPLAIN EXTENDED SELECT f1 FROM t3 WHERE f1 > 30 AND f1 < 33;
|
||||||
--echo # Turn off range access for PRIMARY key
|
--echo # Turn off range access for PRIMARY key
|
||||||
@@ -171,6 +173,7 @@ EXPLAIN EXTENDED
|
|||||||
SELECT * FROM t12, t13 WHERE t12.a=t13.a AND (t13.b+1 <= t13.b+1);
|
SELECT * FROM t12, t13 WHERE t12.a=t13.a AND (t13.b+1 <= t13.b+1);
|
||||||
|
|
||||||
--disable_ps2_protocol
|
--disable_ps2_protocol
|
||||||
|
--disable_cursor_protocol
|
||||||
--echo # Check statistics without hint
|
--echo # Check statistics without hint
|
||||||
FLUSH STATUS;
|
FLUSH STATUS;
|
||||||
SELECT * FROM t12, t13 WHERE t12.a=t13.a AND (t13.b+1 <= t13.b+1);
|
SELECT * FROM t12, t13 WHERE t12.a=t13.a AND (t13.b+1 <= t13.b+1);
|
||||||
@@ -181,6 +184,7 @@ FLUSH STATUS;
|
|||||||
SELECT /*+ BKA() */ * FROM t12, t13 WHERE t12.a=t13.a AND (t13.b+1 <= t13.b+1);
|
SELECT /*+ BKA() */ * FROM t12, t13 WHERE t12.a=t13.a AND (t13.b+1 <= t13.b+1);
|
||||||
SHOW STATUS LIKE 'handler_read%';
|
SHOW STATUS LIKE 'handler_read%';
|
||||||
--enable_ps2_protocol
|
--enable_ps2_protocol
|
||||||
|
--enable_cursor_protocol
|
||||||
|
|
||||||
EXPLAIN EXTENDED SELECT /*+ BKA(t13) */ * FROM t12, t13
|
EXPLAIN EXTENDED SELECT /*+ BKA(t13) */ * FROM t12, t13
|
||||||
WHERE t12.a=t13.a AND (t13.b+1 <= t13.b+1);
|
WHERE t12.a=t13.a AND (t13.b+1 <= t13.b+1);
|
||||||
@@ -355,11 +359,13 @@ WHERE tbl12.a=tbl13.a AND (tbl13.b+1 <= tbl13.b+1);
|
|||||||
--enable_ps_protocol
|
--enable_ps_protocol
|
||||||
|
|
||||||
--disable_ps2_protocol
|
--disable_ps2_protocol
|
||||||
|
--disable_cursor_protocol
|
||||||
--echo # Check that PS and conventional statements give the same result.
|
--echo # Check that PS and conventional statements give the same result.
|
||||||
FLUSH STATUS;
|
FLUSH STATUS;
|
||||||
SELECT /*+ BKA(t13) */ * FROM t12, t13 WHERE t12.a=t13.a AND (t13.b+1 <= t13.b+1);
|
SELECT /*+ BKA(t13) */ * FROM t12, t13 WHERE t12.a=t13.a AND (t13.b+1 <= t13.b+1);
|
||||||
SHOW STATUS LIKE 'handler_read%';
|
SHOW STATUS LIKE 'handler_read%';
|
||||||
--enable_ps2_protocol
|
--enable_ps2_protocol
|
||||||
|
--enable_cursor_protocol
|
||||||
|
|
||||||
PREPARE stmt1 FROM "SELECT /*+ BKA(t13) */ * FROM t12, t13 WHERE t12.a=t13.a AND (t13.b+1 <= t13.b+1)";
|
PREPARE stmt1 FROM "SELECT /*+ BKA(t13) */ * FROM t12, t13 WHERE t12.a=t13.a AND (t13.b+1 <= t13.b+1)";
|
||||||
FLUSH STATUS;
|
FLUSH STATUS;
|
||||||
@@ -388,6 +394,7 @@ CREATE TABLE t3 (a INT, b INT);
|
|||||||
INSERT INTO t3 VALUES (1,1),(2,2);
|
INSERT INTO t3 VALUES (1,1),(2,2);
|
||||||
|
|
||||||
--disable_ps2_protocol
|
--disable_ps2_protocol
|
||||||
|
--disable_cursor_protocol
|
||||||
--echo # Check statistics without hint
|
--echo # Check statistics without hint
|
||||||
FLUSH STATUS;
|
FLUSH STATUS;
|
||||||
SELECT t1.* FROM t1,t2,t3;
|
SELECT t1.* FROM t1,t2,t3;
|
||||||
@@ -398,6 +405,7 @@ FLUSH STATUS;
|
|||||||
SELECT /*+ NO_BNL() */t1.* FROM t1,t2,t3;
|
SELECT /*+ NO_BNL() */t1.* FROM t1,t2,t3;
|
||||||
SHOW STATUS LIKE 'handler_read%';
|
SHOW STATUS LIKE 'handler_read%';
|
||||||
--enable_ps2_protocol
|
--enable_ps2_protocol
|
||||||
|
--enable_cursor_protocol
|
||||||
|
|
||||||
EXPLAIN EXTENDED SELECT t1.* FROM t1,t2,t3;
|
EXPLAIN EXTENDED SELECT t1.* FROM t1,t2,t3;
|
||||||
EXPLAIN EXTENDED SELECT /*+ NO_BNL() */t1.* FROM t1,t2,t3;
|
EXPLAIN EXTENDED SELECT /*+ NO_BNL() */t1.* FROM t1,t2,t3;
|
||||||
@@ -706,6 +714,7 @@ ANALYZE TABLE t1;
|
|||||||
set optimizer_switch='mrr=on,mrr_cost_based=off';
|
set optimizer_switch='mrr=on,mrr_cost_based=off';
|
||||||
|
|
||||||
--disable_ps2_protocol
|
--disable_ps2_protocol
|
||||||
|
--disable_cursor_protocol
|
||||||
--echo # Check statistics without hint
|
--echo # Check statistics without hint
|
||||||
FLUSH STATUS;
|
FLUSH STATUS;
|
||||||
SELECT * FROM t1 WHERE f2 <= 3 AND 3 <= f3;
|
SELECT * FROM t1 WHERE f2 <= 3 AND 3 <= f3;
|
||||||
@@ -725,6 +734,7 @@ SHOW STATUS LIKE 'handler_read%';
|
|||||||
|
|
||||||
DROP PROCEDURE p;
|
DROP PROCEDURE p;
|
||||||
--enable_ps2_protocol
|
--enable_ps2_protocol
|
||||||
|
--enable_cursor_protocol
|
||||||
|
|
||||||
EXPLAIN EXTENDED SELECT * FROM t1 WHERE f2 <= 3 AND 3 <= f3;
|
EXPLAIN EXTENDED SELECT * FROM t1 WHERE f2 <= 3 AND 3 <= f3;
|
||||||
--echo # Turn off MRR. MRR should not be used.
|
--echo # Turn off MRR. MRR should not be used.
|
||||||
|
1856
mysql-test/main/opt_hints_subquery.result
Normal file
1856
mysql-test/main/opt_hints_subquery.result
Normal file
File diff suppressed because it is too large
Load Diff
863
mysql-test/main/opt_hints_subquery.test
Normal file
863
mysql-test/main/opt_hints_subquery.test
Normal file
@@ -0,0 +1,863 @@
|
|||||||
|
--enable_prepare_warnings
|
||||||
|
--disable_view_protocol # Since optimizer hints are not supported inside views
|
||||||
|
CREATE TABLE t1 (a INTEGER NOT NULL, b INT, PRIMARY KEY (a));
|
||||||
|
CREATE TABLE t2 (a INTEGER NOT NULL, KEY (a));
|
||||||
|
CREATE TABLE t3 (a INTEGER NOT NULL, b INT, KEY (a));
|
||||||
|
INSERT INTO t1 VALUES (1,10), (2,20), (3,30), (4,40);
|
||||||
|
INSERT INTO t2 VALUES (2), (3), (4), (5);
|
||||||
|
INSERT INTO t3 VALUES (10,3), (20,4), (30,5);
|
||||||
|
|
||||||
|
ANALYZE TABLE t1, t2, t3;
|
||||||
|
|
||||||
|
--echo # Parser tests
|
||||||
|
--echo # Correct hints (no warnings):
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN() */ a FROM t1;
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ QB_NAME(qb1) SEMIJOIN(@qb1) */ a FROM t1;
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ QB_NAME(qb1) NO_SEMIJOIN(@qb1 firstmatch) */ a FROM t1;
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ QB_NAME(qb1) SEMIJOIN( @qb1 firstmatch, dupsweedout ) */ a FROM t1;
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN( FIRSTMATCH, LOOSESCAN,materialization, DUPSWEEDOUT ) */ a FROM t1;
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ QB_NAME(qb2) NO_SEMIJOIN(@qb2 FIRSTMATCH,LOOSESCAN, materialization, DUPSWEEDOUT) */ a FROM t1;
|
||||||
|
|
||||||
|
set optimizer_switch='derived_merge=off';
|
||||||
|
--echo # Correct 'cause hints refer to different query blocks:
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@qb1) SEMIJOIN(loosescan)*/ a
|
||||||
|
FROM (SELECT /*+ QB_NAME(qb1)*/ * FROM t2) AS tt;
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN()*/ a
|
||||||
|
FROM (SELECT /*+ SEMIJOIN(loosescan)*/ * FROM t2) AS tt;
|
||||||
|
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SUBQUERY(materialization) */ a FROM t1;
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SUBQUERY( INTOEXISTS ) */ a FROM t1;
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ QB_NAME (qb1) SUBQUERY(@qb1 materialization) */ a FROM t1;
|
||||||
|
|
||||||
|
--echo # Incorrect hints (warnings)
|
||||||
|
SELECT /*+ SEMIJOIN(loosescan @qb1) */ a FROM t1;
|
||||||
|
SELECT /*+ SEMIJOIN(@qb1 @qb2) */ a FROM t1;
|
||||||
|
SELECT /*+ SEMIJOIN(@qb1 LOOSESCAN,materialization, unknown_strategy) */ a FROM t1;
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@qb1, @qb2) */ a FROM t1;
|
||||||
|
SELECT /*+ NO_SEMIJOIN(FIRSTMATCH, ,LOOSESCAN, materialization) */ a FROM t1;
|
||||||
|
SELECT /*+ NO_SEMIJOIN(FIRSTMATCH, @qb2,LOOSESCAN) */ a FROM t1;
|
||||||
|
SELECT /*+ SUBQUERY(wrong_strat) */ a FROM t1;
|
||||||
|
SELECT /*+ SUBQUERY(materialization, intoexists) */ a FROM t1;
|
||||||
|
SELECT /*+ SUBQUERY(@qb1 materialization) */ a FROM t1;
|
||||||
|
SELECT /*+ SUBQUERY() */ a FROM t1;
|
||||||
|
|
||||||
|
--echo # Mix of correct and incorrect hints:
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(firstmatch ) SEMIJOIN(loosescan @qb1) */ a FROM t1;
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@qb1, @qb2) SEMIJOIN()*/ a FROM t1;
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN() NO_SEMIJOIN(FIRSTMATCH, @qb2,LOOSESCAN) */ a FROM t1;
|
||||||
|
|
||||||
|
--echo # Conflicting hints:
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN() SEMIJOIN(dupsweedout) NO_SEMIJOIN(firstmatch)*/ a FROM t1;
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(loosescan,materialization) SEMIJOIN(dupsweedout)*/ a FROM t1;
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(firstmatch,loosescan,materialization) SEMIJOIN() NO_SEMIJOIN()*/ a
|
||||||
|
FROM t1;
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ QB_NAME(qb1) SEMIJOIN(@qb1) SEMIJOIN(loosescan) NO_SEMIJOIN(@qb1 dupsweedout)*/ a
|
||||||
|
FROM t1;
|
||||||
|
EXPLAIN EXTENDED SELECT /*+ SEMIJOIN(firstmatch) NO_SEMIJOIN()*/ a FROM t1;
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SUBQUERY(materialization) SUBQUERY(intoexists)*/ a FROM t1;
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN() SUBQUERY(materialization) SUBQUERY(intoexists)*/ a FROM t1;
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SUBQUERY(materialization) SUBQUERY(intoexists)*/ a FROM t1;
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SUBQUERY(materialization) SUBQUERY(intoexists) SUBQUERY(materialization)*/ a
|
||||||
|
FROM t1;
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SUBQUERY(materialization) SEMIJOIN(firstmatch) SUBQUERY(intoexists)*/ a FROM t1;
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ QB_NAME(qb1) SEMIJOIN(@qb1) SUBQUERY(@qb1 materialization) SUBQUERY(intoexists)*/ a FROM t1;
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ QB_NAME(qb1) SUBQUERY(@qb1 materialization) SEMIJOIN(@qb1 firstmatch) SUBQUERY(intoexists)*/ a FROM t1;
|
||||||
|
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@qb1) SEMIJOIN(loosescan) NO_SEMIJOIN(@qb1 dupsweedout)*/ a
|
||||||
|
FROM (SELECT /*+ QB_NAME(qb1)*/ * FROM t2) AS tt;
|
||||||
|
|
||||||
|
DROP TABLE t1, t2 ,t3;
|
||||||
|
set optimizer_switch=default;
|
||||||
|
--echo # End of parser tests
|
||||||
|
|
||||||
|
CREATE TABLE t1 (a INTEGER NOT NULL, b INT, PRIMARY KEY (a));
|
||||||
|
CREATE TABLE t2 (a INTEGER NOT NULL, KEY (a));
|
||||||
|
CREATE TABLE t3 (a INTEGER NOT NULL, b INT, KEY (a));
|
||||||
|
INSERT INTO t1 VALUES (1,10), (2,20), (3,30), (4,40);
|
||||||
|
INSERT INTO t2 VALUES (2), (2), (3), (3), (4), (5);
|
||||||
|
INSERT INTO t3 VALUES (10,3), (15,3), (20,4), (30,5);
|
||||||
|
|
||||||
|
ANALYZE TABLE t1, t2, t3;
|
||||||
|
|
||||||
|
--echo # This query will normally use Table Pull-out
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT * FROM t2 WHERE t2.a IN (SELECT a FROM t1);
|
||||||
|
--echo # Check that we can disable SEMIJOIN transformation
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT * FROM t2 WHERE t2.a IN (SELECT /*+ NO_SEMIJOIN() */ a FROM t1);
|
||||||
|
--echo # Same with hint in outer query
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq) */ a FROM t1);
|
||||||
|
|
||||||
|
--echo # Query with two sub-queries
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT * FROM t3
|
||||||
|
WHERE t3.a IN (SELECT a FROM t1 tx)
|
||||||
|
AND t3.b IN (SELECT a FROM t1 ty);
|
||||||
|
--echo # No SEMIJOIN transformation for first subquery
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT * FROM t3
|
||||||
|
WHERE t3.a IN (SELECT /*+ NO_SEMIJOIN() */ a FROM t1 tx)
|
||||||
|
AND t3.b IN (SELECT a FROM t1 ty);
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq1) */ * FROM t3
|
||||||
|
WHERE t3.a IN (SELECT /*+ QB_NAME(`subq1`) */ a FROM t1 tx)
|
||||||
|
AND t3.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t1 ty);
|
||||||
|
--echo # No SEMIJOIN transformation for latter subquery
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT * FROM t3
|
||||||
|
WHERE t3.a IN (SELECT a FROM t1 tx)
|
||||||
|
AND t3.b IN (SELECT /*+ NO_SEMIJOIN() */ a FROM t1 ty);
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@`subq2`) */ * FROM t3
|
||||||
|
WHERE t3.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t1 tx)
|
||||||
|
AND t3.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t1 ty);
|
||||||
|
--echo # No SEMIJOIN transformation for any subquery
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT * FROM t3
|
||||||
|
WHERE t3.a IN (SELECT /*+ NO_SEMIJOIN() */ a FROM t1 tx)
|
||||||
|
AND t3.b IN (SELECT /*+ NO_SEMIJOIN() */ a FROM t1 ty);
|
||||||
|
EXPLAIN
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq1) NO_SEMIJOIN(@subq2) */ * FROM t3
|
||||||
|
WHERE t3.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t1 tx)
|
||||||
|
AND t3.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t1 ty);
|
||||||
|
|
||||||
|
--echo # Query with nested sub-queries
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT * FROM t3
|
||||||
|
WHERE t3.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t1 tx
|
||||||
|
WHERE tx.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t1 ty));
|
||||||
|
--echo # No SEMIJOIN transformation for outer subquery
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq1) */ * FROM t3
|
||||||
|
WHERE t3.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t1 tx
|
||||||
|
WHERE tx.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t1 ty));
|
||||||
|
--echo # No SEMIJOIN transformation for inner-most subquery
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq2) */ * FROM t3
|
||||||
|
WHERE t3.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t1 tx
|
||||||
|
WHERE tx.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t1 ty));
|
||||||
|
--echo # No SEMIJOIN transformation at all
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq1) NO_SEMIJOIN(@subq2) */ * FROM t3
|
||||||
|
WHERE t3.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t1 tx
|
||||||
|
WHERE tx.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t1 ty));
|
||||||
|
|
||||||
|
--echo # This query does not support SEMIJOIN. SEMIJOIN hint is ignored
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq) */ min(a) FROM t1 group by a);
|
||||||
|
|
||||||
|
--echo # This query will get LooseScan by default
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
|
||||||
|
--echo # Let's turn off LooseScan, FirstMatch is then SELECTed
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq1 LOOSESCAN) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
|
||||||
|
--echo # Let's also turn off FirstMatch, DupsWeedout is then used.
|
||||||
|
--echo # (StartTemporary, EndTemporary) in the output indicate DupsWeedout usage
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq1 FIRSTMATCH, LOOSESCAN) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
|
||||||
|
--echo # Materialization is used here
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq1 FIRSTMATCH, LOOSESCAN, DUPSWEEDOUT) */ *
|
||||||
|
FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
|
||||||
|
--echo # Turn off all strategies, DuplicateWeedout should be used as a fallback
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq1 FIRSTMATCH, LOOSESCAN, MATERIALIZATION,
|
||||||
|
DUPSWEEDOUT) */ *
|
||||||
|
FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
|
||||||
|
--echo # Turn off non-used strategies, nothing should change. Still Loosescan
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq1 FIRSTMATCH, MATERIALIZATION, DUPSWEEDOUT) */ *
|
||||||
|
FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
|
||||||
|
|
||||||
|
--echo # Test same query with SEMIJOIN hint
|
||||||
|
--echo # Forcing LooseScan, should not change anything
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
|
||||||
|
--echo # Force FirstMatch
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 FIRSTMATCH) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
|
||||||
|
--echo # Force Materialization
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 MATERIALIZATION) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
|
||||||
|
--echo # Force DuplicateWeedout
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 DUPSWEEDOUT) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
|
||||||
|
--echo # If LooseScan is among candidates, it will be used
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN, DUPSWEEDOUT) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN, MATERIALIZATION, DUPSWEEDOUT) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN, FIRSTMATCH, MATERIALIZATION,
|
||||||
|
DUPSWEEDOUT) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
|
||||||
|
--echo # Drop LooseScan from list of strategies, FirstMatch will be used
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 FIRSTMATCH, MATERIALIZATION, DUPSWEEDOUT) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
|
||||||
|
|
||||||
|
--echo For this query LooseScan and Materialization is not applicable
|
||||||
|
# Warnings "Field or reference <fx> of SELECT #n was resolved in SELECT #m"
|
||||||
|
# are generated during both prepare and execution stages. So disable PS protocol
|
||||||
|
# to avoid duplication
|
||||||
|
--disable_ps_protocol
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT * FROM t1
|
||||||
|
WHERE t1.b IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3 WHERE t3.b = t1.a);
|
||||||
|
--echo # Turn off all applicable strategies. DuplicateWeedout should be used
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq1 FIRSTMATCH, DUPSWEEDOUT) */ * FROM t1
|
||||||
|
WHERE t1.b IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3 WHERE t3.b = t1.a);
|
||||||
|
--echo # Similar with SEMIJOIN hint
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN, MATERIALIZATION) */ * FROM t1
|
||||||
|
WHERE t1.b IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3 WHERE t3.b = t1.a);
|
||||||
|
--enable_ps_protocol
|
||||||
|
|
||||||
|
--echo # Test multiple subqueries.
|
||||||
|
--echo # Default for this query is Loosecan for first and FirstMatch for latter
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2);
|
||||||
|
--echo # Forcing the default strategy should not change anything
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN) SEMIJOIN(@subq2 FIRSTMATCH) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2);
|
||||||
|
--echo # Forcing a strategy for one, may change the other due to cost changes
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 FIRSTMATCH) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2);
|
||||||
|
--echo # Forcing same strategy for both
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 FIRSTMATCH) SEMIJOIN(@subq2 FIRSTMATCH) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2);
|
||||||
|
--echo # Loosescan for both is not possible, ends up with DuplicateWeedout
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN) SEMIJOIN(@subq2 LOOSESCAN) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2);
|
||||||
|
--echo # Swap strategies compared to default
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 FIRSTMATCH) SEMIJOIN(@subq2 LOOSESCAN) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2);
|
||||||
|
--echo # Different subsets of strategies for different subqueries
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 FIRSTMATCH, LOOSESCAN)
|
||||||
|
SEMIJOIN(@subq2 MATERIALIZATION, DUPSWEEDOUT) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2);
|
||||||
|
--echo # Vice versa
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 MATERIALIZATION, DUPSWEEDOUT)
|
||||||
|
SEMIJOIN(@subq2 FIRSTMATCH, LOOSESCAN) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2);
|
||||||
|
--echo # Another combination
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 MATERIALIZATION, FIRSTMATCH)
|
||||||
|
SEMIJOIN(@subq2 LOOSESCAN, DUPSWEEDOUT) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2);
|
||||||
|
--echo # Turn off default
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq1 LOOSESCAN)
|
||||||
|
NO_SEMIJOIN(@subq2 FIRSTMATCH) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2);
|
||||||
|
--echo # Also turn off 2nd choice. Gives DuplicateWeedout over both
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq1 LOOSESCAN, FIRSTMATCH)
|
||||||
|
NO_SEMIJOIN(@subq2 FIRSTMATCH, LOOSESCAN) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2);
|
||||||
|
--echo # Also turn off DuplicateWeedout. Materialization is only one left.
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq1 LOOSESCAN, FIRSTMATCH, DUPSWEEDOUT)
|
||||||
|
NO_SEMIJOIN(@subq2 FIRSTMATCH, LOOSESCAN, DUPSWEEDOUT) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2);
|
||||||
|
--echo # Force materialization with SEMIJOIN hints instead
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 MATERIALIZATION)
|
||||||
|
SEMIJOIN(@subq2 MATERIALIZATION) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2);
|
||||||
|
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 MATERIALIZATION)
|
||||||
|
SEMIJOIN(@subq2 DUPSWEEDOUT) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2);
|
||||||
|
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 MATERIALIZATION)
|
||||||
|
SEMIJOIN(@subq2 LOOSESCAN, FIRSTMATCH, DUPSWEEDOUT) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2);
|
||||||
|
|
||||||
|
--echo # A query with nested subqueries which are joined together
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3
|
||||||
|
WHERE t3.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2));
|
||||||
|
--echo # Let's turn off FirtMatch, DuplicateWeedout is then chosen
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq1 FIRSTMATCH) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3
|
||||||
|
WHERE t3.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2));
|
||||||
|
--echo # If we turn off all strategies, DuplicateWeedout should still be used
|
||||||
|
EXPLAIN
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq1 FIRSTMATCH, LOOSESCAN, MATERIALIZATION,
|
||||||
|
DUPSWEEDOUT) */ *
|
||||||
|
FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3
|
||||||
|
WHERE t3.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2));
|
||||||
|
|
||||||
|
--echo # Test the same query with SEMIJOIN hint
|
||||||
|
--echo # Force FirstMatch, should not change anything
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 FIRSTMATCH) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3
|
||||||
|
WHERE t3.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2));
|
||||||
|
--echo # Force LooseScan, will fall back to DuplicateWeedout
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3
|
||||||
|
WHERE t3.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2));
|
||||||
|
--echo # Force DuplicateWeedout
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 DUPSWEEDOUT) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3
|
||||||
|
WHERE t3.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2));
|
||||||
|
--echo # If FirstMatch is among candidates, it will be used
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 FIRSTMATCH, DUPSWEEDOUT) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3
|
||||||
|
WHERE t3.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2));
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 MATERIALIZATION, FIRSTMATCH, LOOSESCAN,
|
||||||
|
DUPSWEEDOUT) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3
|
||||||
|
WHERE t3.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2));
|
||||||
|
|
||||||
|
--echo # Test hints with prepared statements
|
||||||
|
PREPARE stmt1 FROM "EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq1 FIRSTMATCH, LOOSESCAN)
|
||||||
|
NO_SEMIJOIN(@subq2 FIRSTMATCH, LOOSESCAN) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2)";
|
||||||
|
EXECUTE stmt1;
|
||||||
|
EXECUTE stmt1;
|
||||||
|
DEALLOCATE PREPARE stmt1;
|
||||||
|
|
||||||
|
SET optimizer_switch = default;
|
||||||
|
|
||||||
|
--echo # Tests with non-default optimizer_switch settings
|
||||||
|
|
||||||
|
SET optimizer_switch = 'semijoin=off';
|
||||||
|
--echo # No table pull-out for this query
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT * FROM t2 WHERE t2.a IN (SELECT a FROM t1);
|
||||||
|
--echo # This should not change anything
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq) */ a FROM t1);
|
||||||
|
--echo # Force semijoin, table pull-out is performed
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq) */ a FROM t1);
|
||||||
|
--echo # Setting strategy should still force semijoin
|
||||||
|
--echo # Strategy is ignored since table pull-out is done
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq FIRSTMATCH) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq) */ a FROM t1);
|
||||||
|
|
||||||
|
--echo # Query with two sub-queries
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT * FROM t3
|
||||||
|
WHERE t3.a IN (SELECT a FROM t1 tx)
|
||||||
|
AND t3.b IN (SELECT a FROM t1 ty);
|
||||||
|
--echo # SEMIJOIN transformation for first subquery
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1) */ * FROM t3
|
||||||
|
WHERE t3.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t1 tx)
|
||||||
|
AND t3.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t1 ty);
|
||||||
|
--echo # SEMIJOIN transformation for latter subquery
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq2) */ * FROM t3
|
||||||
|
WHERE t3.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t1 tx)
|
||||||
|
AND t3.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t1 ty);
|
||||||
|
--echo # SEMIJOIN transformation for both subqueries
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1) SEMIJOIN(@subq2) */ * FROM t3
|
||||||
|
WHERE t3.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t1 tx)
|
||||||
|
AND t3.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t1 ty);
|
||||||
|
|
||||||
|
--echo # Query with nested sub-queries
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT * FROM t3
|
||||||
|
WHERE t3.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t1 tx
|
||||||
|
WHERE tx.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t1 ty));
|
||||||
|
--echo # SEMIJOIN transformation for outer subquery
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1) */ * FROM t3
|
||||||
|
WHERE t3.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t1 tx
|
||||||
|
WHERE tx.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t1 ty));
|
||||||
|
--echo # SEMIJOIN transformation for inner-most subquery
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq2) */ * FROM t3
|
||||||
|
WHERE t3.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t1 tx
|
||||||
|
WHERE tx.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t1 ty));
|
||||||
|
--echo # SEMIJOIN transformation for both
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1) SEMIJOIN(@subq2) */ * FROM t3
|
||||||
|
WHERE t3.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t1 tx
|
||||||
|
WHERE tx.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t1 ty));
|
||||||
|
|
||||||
|
--echo Test strategies when some are disabled by optimizer_switch
|
||||||
|
SET optimizer_switch='semijoin=on';
|
||||||
|
SET optimizer_switch='loosescan=off';
|
||||||
|
--echo # This query will get LooseScan by default. FirstMatch now
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
|
||||||
|
--echo # Let's turn off LooseScan also by hint, FirstMatch is then selected
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq1 LOOSESCAN) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
|
||||||
|
--echo # Let's also turn off FirstMatch, DupsWeedout is then used.
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq1 FIRSTMATCH) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
|
||||||
|
--echo # Turn off DupsWeedout, Materialization is used here
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq1 FIRSTMATCH, DUPSWEEDOUT) */ *
|
||||||
|
FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
|
||||||
|
|
||||||
|
--echo # Let's force LooseScan back on
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
|
||||||
|
--echo # Forcing another strategy
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 MATERIALIZATION) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
|
||||||
|
--echo # If LooseScan is among candidates, it is used even if originally disabled
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN, DUPSWEEDOUT) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN, MATERIALIZATION, DUPSWEEDOUT) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN, FIRSTMATCH, MATERIALIZATION,
|
||||||
|
DUPSWEEDOUT) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
|
||||||
|
|
||||||
|
--echo Disable another strategy
|
||||||
|
SET optimizer_switch='firstmatch=off';
|
||||||
|
|
||||||
|
--echo # Turn on FirstMatch, but not LooseScan on with hint
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 FIRSTMATCH, MATERIALIZATION, DUPSWEEDOUT) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
|
||||||
|
--echo # Drop all remaining strategies with hint, should use DuplicateWeedout
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq1 MATERIALIZATION, DUPSWEEDOUT) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
|
||||||
|
|
||||||
|
--echo # For this query LooseScan and Materialization is not applicable
|
||||||
|
--echo # Should use DuplicateWeedout since FirstMatch is disabled
|
||||||
|
# Warnings "Field or reference <fx> of SELECT #n was resolved in SELECT #m"
|
||||||
|
# are generated during both prepare and execution stages. So disable PS protocol
|
||||||
|
# to avoid duplication
|
||||||
|
--disable_ps_protocol
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT * FROM t1
|
||||||
|
WHERE t1.b IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3 WHERE t3.b = t1.a);
|
||||||
|
--echo Turn off all applicable strategies. DuplicateWeedout should still be used
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq1 FIRSTMATCH, DUPSWEEDOUT) */ * FROM t1
|
||||||
|
WHERE t1.b IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3 WHERE t3.b = t1.a);
|
||||||
|
--echo Reverse which strategies are allowed with hint
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN, FIRSTMATCH) */ * FROM t1
|
||||||
|
WHERE t1.b IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3 WHERE t3.b = t1.a);
|
||||||
|
--enable_ps_protocol
|
||||||
|
|
||||||
|
--echo # Default for this query is Loosecan for first and FirstMatch for latter
|
||||||
|
--echo # Since both strategies are disabled, will now use DuplicateWeedout
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2);
|
||||||
|
--echo # Allowing LooseScan and FirstMatch and optimizer_switch is ignored
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN, FIRSTMATCH)
|
||||||
|
SEMIJOIN(@subq2 LOOSESCAN, FIRSTMATCH) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2);
|
||||||
|
--echo # Forcing a disabled strategy for one
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 FIRSTMATCH) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2);
|
||||||
|
--echo # Forcing same strategy for both
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 FIRSTMATCH) SEMIJOIN(@subq2 FIRSTMATCH) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2);
|
||||||
|
--echo # Swap strategies compared to default
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 FIRSTMATCH) SEMIJOIN(@subq2 LOOSESCAN) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2);
|
||||||
|
--echo # Different subsets of strategies for different subqueries
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 FIRSTMATCH, LOOSESCAN)
|
||||||
|
SEMIJOIN(@subq2 MATERIALIZATION, DUPSWEEDOUT) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2);
|
||||||
|
--echo # Turn off DuplicateWeedout for both. Materialization is left
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq1 DUPSWEEDOUT)
|
||||||
|
NO_SEMIJOIN(@subq2 DUPSWEEDOUT) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2);
|
||||||
|
--echo # Forcing materialization should have same effect
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 MATERIALIZATION)
|
||||||
|
SEMIJOIN(@subq2 MATERIALIZATION) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2);
|
||||||
|
--echo # Turn off DuplicateWeedout for first. MatLookup is used for both
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq1 DUPSWEEDOUT) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2);
|
||||||
|
--echo # Turn off DuplicateWeedout for second. Same effect.
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq2 DUPSWEEDOUT) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2);
|
||||||
|
|
||||||
|
--echo Enable all strategies except DuplicateWeedout
|
||||||
|
SET optimizer_switch='firstmatch=on,loosescan=on,materialization=on,duplicateweedout=off';
|
||||||
|
|
||||||
|
--echo # If we turn off all other strategies, DuplicateWeedout will be used
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq1 LOOSESCAN, FIRSTMATCH, MATERIALIZATION) */ *
|
||||||
|
FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
|
||||||
|
--echo # LooseScan and Materialization is not applicable, FirstMatch is used
|
||||||
|
# Warnings "Field or reference <fx> of SELECT #n was resolved in SELECT #m"
|
||||||
|
# are generated during both prepare and execution stages. So disable PS protocol
|
||||||
|
# to avoid duplication
|
||||||
|
--disable_ps_protocol
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT * FROM t1
|
||||||
|
WHERE t1.b IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3 WHERE t3.b = t1.a);
|
||||||
|
--echo # Turn off all applicable strategies. DuplicateWeedout should be used
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq1 FIRSTMATCH) */ * FROM t1
|
||||||
|
WHERE t1.b IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3 WHERE t3.b = t1.a);
|
||||||
|
--echo # Similar with SEMIJOIN hint
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN, MATERIALIZATION) */ * FROM t1
|
||||||
|
WHERE t1.b IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3 WHERE t3.b = t1.a);
|
||||||
|
--enable_ps_protocol
|
||||||
|
|
||||||
|
--echo # Disable all strategies
|
||||||
|
SET optimizer_switch='firstmatch=off,loosescan=off,materialization=off,duplicateweedout=off';
|
||||||
|
--echo # DuplicateWeedout is then used
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
|
||||||
|
--echo # Turning off extra strategies should not change anything
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq1 LOOSESCAN, DUPSWEEDOUT) */ *
|
||||||
|
FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
|
||||||
|
--echo # Turning on some strategies should give one of those
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 FIRSTMATCH, MATERIALIZATION) */ *
|
||||||
|
FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
|
||||||
|
--echo # For this query that cannot use LooseScan or Materialization,
|
||||||
|
--echo # turning those on will still give DuplicateWeedout
|
||||||
|
# Warnings "Field or reference <fx> of SELECT #n was resolved in SELECT #m"
|
||||||
|
# are generated during both prepare and execution stages. So disable PS protocol
|
||||||
|
# to avoid duplication
|
||||||
|
--disable_ps_protocol
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN, MATERIALIZATION) */ * FROM t1
|
||||||
|
WHERE t1.b IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3 WHERE t3.b = t1.a);
|
||||||
|
--echo # Turning on FirstMatch should give FirstMatch
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN, FIRSTMATCH) */ * FROM t1
|
||||||
|
WHERE t1.b IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3 WHERE t3.b = t1.a);
|
||||||
|
--enable_ps_protocol
|
||||||
|
|
||||||
|
SET optimizer_switch = default;
|
||||||
|
|
||||||
|
--echo Test that setting optimizer_switch after prepare will change strategy
|
||||||
|
PREPARE stmt1 FROM "EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq1 FIRSTMATCH, LOOSESCAN)
|
||||||
|
NO_SEMIJOIN(@subq2 FIRSTMATCH, LOOSESCAN) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2)";
|
||||||
|
EXECUTE stmt1;
|
||||||
|
SET optimizer_switch = 'duplicateweedout=off';
|
||||||
|
--echo Will now use materialization
|
||||||
|
EXECUTE stmt1;
|
||||||
|
SET optimizer_switch = 'duplicateweedout=on';
|
||||||
|
--echo Turn DuplicateWeedout back on
|
||||||
|
EXECUTE stmt1;
|
||||||
|
DEALLOCATE PREPARE stmt1;
|
||||||
|
|
||||||
|
SET optimizer_switch = default;
|
||||||
|
|
||||||
|
--echo # Specifying two SEMIJOIN/NO_SEMIJOIN for same query block gives warning
|
||||||
|
--echo # First has effect, second is ignored
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ NO_SEMIJOIN() SEMIJOIN() */ a FROM t1);
|
||||||
|
--echo # Try opposite order
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ SEMIJOIN() NO_SEMIJOIN() */ a FROM t1);
|
||||||
|
--echo # Specify at different levels, hint inside block has effect
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq) SEMIJOIN() */ a FROM t1);
|
||||||
|
--echo # Specify at different levels, opposite order
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq) NO_SEMIJOIN() */ a FROM t1);
|
||||||
|
--echo # Duplicate hints also gives warning, but hint has effect
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq) SEMIJOIN() */ a FROM t1);
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq) NO_SEMIJOIN() */ a FROM t1);
|
||||||
|
|
||||||
|
--echo # Multiple subqueries with conflicting hints
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN) SEMIJOIN(@subq2 FIRSTMATCH) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) NO_SEMIJOIN() */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) SEMIJOIN(LOOSESCAN) */ a FROM t2);
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN) SEMIJOIN(@subq2 FIRSTMATCH) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) NO_SEMIJOIN(LOOSESCAN) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) SEMIJOIN(LOOSESCAN) */ a FROM t2);
|
||||||
|
--echo # Conflicting hints in same hint comment
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN) SEMIJOIN(@subq1 FIRSTMATCH) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2);
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN) NO_SEMIJOIN(@subq1 LOOSESCAN) */ *
|
||||||
|
FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2);
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ NO_SEMIJOIN(@subq1 LOOSESCAN) NO_SEMIJOIN(@subq1 FIRSTMATCH) */ *
|
||||||
|
FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2);
|
||||||
|
|
||||||
|
--echo # Non-supported strategies should give warnings
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq1 INTOEXISTS) NO_SEMIJOIN(@subq2 INTOEXISTS) */ *
|
||||||
|
FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2);
|
||||||
|
|
||||||
|
--echo # SUBQUERY tests
|
||||||
|
--echo # SUBQUERY should disable SEMIJOIN and use specified subquery strategy
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT * FROM t2 WHERE t2.a IN (SELECT /*+ SUBQUERY(INTOEXISTS) */ a FROM t1);
|
||||||
|
EXPLAIN
|
||||||
|
SELECT /*+ SUBQUERY(@subq MATERIALIZATION) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq) */ a FROM t1);
|
||||||
|
--echo # Query with two subqueries
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SUBQUERY(@subq1 INTOEXISTS) SUBQUERY(@subq2 MATERIALIZATION) */ *
|
||||||
|
FROM t3
|
||||||
|
WHERE t3.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t1 tx)
|
||||||
|
AND t3.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t1 ty);
|
||||||
|
--echo # Query with nested sub-queries
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SUBQUERY(@subq1 INTOEXISTS) SUBQUERY(@subq2 MATERIALIZATION) */ *
|
||||||
|
FROM t3
|
||||||
|
WHERE t3.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t1 tx
|
||||||
|
WHERE tx.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t1 ty));
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SUBQUERY(@subq1 MATERIALIZATION) SUBQUERY(@subq2 INTOEXISTS) */ *
|
||||||
|
FROM t3
|
||||||
|
WHERE t3.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t1 tx
|
||||||
|
WHERE tx.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t1 ty));
|
||||||
|
|
||||||
|
--echo # This query does not support SEMIJOIN. Materialization is default
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq) */ min(a) FROM t1 group by a);
|
||||||
|
--echo # Use In-to-exists instead
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SUBQUERY(@subq INTOEXISTS) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq) */ min(a) FROM t1 group by a);
|
||||||
|
|
||||||
|
--echo # For this query In-to-exists is default
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT a, a IN (SELECT a FROM t1) FROM t2;
|
||||||
|
--echo # Force Subquery Materialization
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT a, a IN (SELECT /*+ SUBQUERY(MATERIALIZATION) */ a FROM t1) FROM t2;
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SUBQUERY(@subq MATERIALIZATION) */ a,
|
||||||
|
a IN (SELECT /*+ QB_NAME(subq) */ a FROM t1) FROM t2;
|
||||||
|
|
||||||
|
--echo # This query does not support Subquery Materialization due to type mismatch
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq) */ sum(b) FROM t1 group by a);
|
||||||
|
--echo # Trying to force Subquery Materialization will not change anything
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SUBQUERY(@subq MATERIALIZATION) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq) */ sum(b) FROM t1 group by a);
|
||||||
|
|
||||||
|
--echo # Test hints with prepared statements
|
||||||
|
PREPARE stmt1 FROM "EXPLAIN
|
||||||
|
SELECT /*+ SUBQUERY(@subq1 MATERIALIZATION)
|
||||||
|
SUBQUERY(@subq2 INTOEXISTS) */ * FROM t1
|
||||||
|
WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3)
|
||||||
|
AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2)";
|
||||||
|
EXECUTE stmt1;
|
||||||
|
EXECUTE stmt1;
|
||||||
|
DEALLOCATE PREPARE stmt1;
|
||||||
|
|
||||||
|
--echo # Test optimizer_switch settings with SUBQUERY hint
|
||||||
|
SET optimizer_switch='materialization=off';
|
||||||
|
--echo This query will now use In-to-exist
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq) */ min(a) FROM t1 group by a);
|
||||||
|
--echo # Force it to use Materialization
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SUBQUERY(@subq MATERIALIZATION) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq) */ min(a) FROM t1 group by a);
|
||||||
|
|
||||||
|
SET optimizer_switch='materialization=on';
|
||||||
|
--echo # This query will now use In-to_exists
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT a, a IN (SELECT a FROM t1) FROM t2;
|
||||||
|
--echo Force Materialization
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SUBQUERY(@subq MATERIALIZATION) */ a,
|
||||||
|
a IN (SELECT /*+ QB_NAME(subq) */ a FROM t1) FROM t2;
|
||||||
|
|
||||||
|
--echo # Specifying both strategies should give a warning
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SUBQUERY(@subq1 MATERIALIZATION, INTOEXISTS)
|
||||||
|
SUBQUERY(@subq2 MATERIALIZATION, INTOEXISTS) */ *
|
||||||
|
FROM t3
|
||||||
|
WHERE t3.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t1 tx)
|
||||||
|
AND t3.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t1 ty);
|
||||||
|
--echo # Non-supported strategies should give warnings
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SUBQUERY(@subq1 FIRSTMATCH) SUBQUERY(@subq2 LOOSESCAN) */ *
|
||||||
|
FROM t3
|
||||||
|
WHERE t3.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t1 tx)
|
||||||
|
AND t3.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t1 ty);
|
||||||
|
|
||||||
|
SET optimizer_switch= default;
|
||||||
|
|
||||||
|
--echo # Specifying two SUBQUERY for same query block gives warning
|
||||||
|
--echo # First has effect, second is ignored
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ SUBQUERY(MATERIALIZATION) SUBQUERY(INTOEXISTS) */ a
|
||||||
|
FROM t1);
|
||||||
|
--echo # Try opposite order
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ SUBQUERY(INTOEXISTS) SUBQUERY(MATERIALIZATION) */ a
|
||||||
|
FROM t1);
|
||||||
|
--echo # Specify at different levels, hint inside block has effect
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SUBQUERY(@subq MATERIALIZATION) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq) SUBQUERY(INTOEXISTS) */ a FROM t1);
|
||||||
|
--echo # Specify at different levels, opposite order
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SUBQUERY(@subq INTOEXISTS) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq) SUBQUERY(MATERIALIZATION) */ a FROM t1);
|
||||||
|
|
||||||
|
--echo # Specifying combinations of SUBQUERY and SEMIJOIN/NO_SEMIJOIN
|
||||||
|
--echo # for same query block gives warning
|
||||||
|
--echo # First has effect, second is ignored
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ SUBQUERY(INTOEXISTS) SEMIJOIN() */ a FROM t1);
|
||||||
|
--echo # Try opposite order
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ NO_SEMIJOIN() SUBQUERY(MATERIALIZATION) */ a FROM t1);
|
||||||
|
--echo # Specify at different levels, hint inside block has effect
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SUBQUERY(@subq MATERIALIZATION) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq) SEMIJOIN() */ a FROM t1);
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SUBQUERY(@subq INTOEXISTS) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq) NO_SEMIJOIN() */ a FROM t1);
|
||||||
|
EXPLAIN EXTENDED
|
||||||
|
SELECT /*+ SEMIJOIN(@subq FIRSTMATCH) */ * FROM t2
|
||||||
|
WHERE t2.a IN (SELECT /*+ QB_NAME(subq) SUBQUERY(@subq INTOEXISTS) */ a FROM t1);
|
||||||
|
|
||||||
|
DROP TABLE t1,t2,t3;
|
||||||
|
|
@@ -1,58 +1,58 @@
|
|||||||
set @@global.optimizer_switch=@@optimizer_switch;
|
set @@global.optimizer_switch=@@optimizer_switch;
|
||||||
select @@global.optimizer_switch;
|
select @@global.optimizer_switch;
|
||||||
@@global.optimizer_switch
|
@@global.optimizer_switch
|
||||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on,rowid_filter=on,condition_pushdown_from_having=on,not_null_range_scan=off,hash_join_cardinality=on,cset_narrowing=on,sargable_casefold=on
|
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,duplicateweedout=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on,rowid_filter=on,condition_pushdown_from_having=on,not_null_range_scan=off,hash_join_cardinality=on,cset_narrowing=on,sargable_casefold=on
|
||||||
select @@session.optimizer_switch;
|
select @@session.optimizer_switch;
|
||||||
@@session.optimizer_switch
|
@@session.optimizer_switch
|
||||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on,rowid_filter=on,condition_pushdown_from_having=on,not_null_range_scan=off,hash_join_cardinality=on,cset_narrowing=on,sargable_casefold=on
|
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,duplicateweedout=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on,rowid_filter=on,condition_pushdown_from_having=on,not_null_range_scan=off,hash_join_cardinality=on,cset_narrowing=on,sargable_casefold=on
|
||||||
show global variables like 'optimizer_switch';
|
show global variables like 'optimizer_switch';
|
||||||
Variable_name Value
|
Variable_name Value
|
||||||
optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on,rowid_filter=on,condition_pushdown_from_having=on,not_null_range_scan=off,hash_join_cardinality=on,cset_narrowing=on,sargable_casefold=on
|
optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,duplicateweedout=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on,rowid_filter=on,condition_pushdown_from_having=on,not_null_range_scan=off,hash_join_cardinality=on,cset_narrowing=on,sargable_casefold=on
|
||||||
show session variables like 'optimizer_switch';
|
show session variables like 'optimizer_switch';
|
||||||
Variable_name Value
|
Variable_name Value
|
||||||
optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on,rowid_filter=on,condition_pushdown_from_having=on,not_null_range_scan=off,hash_join_cardinality=on,cset_narrowing=on,sargable_casefold=on
|
optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,duplicateweedout=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on,rowid_filter=on,condition_pushdown_from_having=on,not_null_range_scan=off,hash_join_cardinality=on,cset_narrowing=on,sargable_casefold=on
|
||||||
select * from information_schema.global_variables where variable_name='optimizer_switch';
|
select * from information_schema.global_variables where variable_name='optimizer_switch';
|
||||||
VARIABLE_NAME VARIABLE_VALUE
|
VARIABLE_NAME VARIABLE_VALUE
|
||||||
OPTIMIZER_SWITCH index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on,rowid_filter=on,condition_pushdown_from_having=on,not_null_range_scan=off,hash_join_cardinality=on,cset_narrowing=on,sargable_casefold=on
|
OPTIMIZER_SWITCH index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,duplicateweedout=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on,rowid_filter=on,condition_pushdown_from_having=on,not_null_range_scan=off,hash_join_cardinality=on,cset_narrowing=on,sargable_casefold=on
|
||||||
select * from information_schema.session_variables where variable_name='optimizer_switch';
|
select * from information_schema.session_variables where variable_name='optimizer_switch';
|
||||||
VARIABLE_NAME VARIABLE_VALUE
|
VARIABLE_NAME VARIABLE_VALUE
|
||||||
OPTIMIZER_SWITCH index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on,rowid_filter=on,condition_pushdown_from_having=on,not_null_range_scan=off,hash_join_cardinality=on,cset_narrowing=on,sargable_casefold=on
|
OPTIMIZER_SWITCH index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,duplicateweedout=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on,rowid_filter=on,condition_pushdown_from_having=on,not_null_range_scan=off,hash_join_cardinality=on,cset_narrowing=on,sargable_casefold=on
|
||||||
set global optimizer_switch=2053;
|
set global optimizer_switch=4101;
|
||||||
set session optimizer_switch=1034;
|
set session optimizer_switch=2058;
|
||||||
select @@global.optimizer_switch;
|
select @@global.optimizer_switch;
|
||||||
@@global.optimizer_switch
|
@@global.optimizer_switch
|
||||||
index_merge=on,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=on,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off,condition_pushdown_from_having=off,not_null_range_scan=off,hash_join_cardinality=off,cset_narrowing=off,sargable_casefold=off
|
index_merge=on,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,duplicateweedout=off,materialization=off,in_to_exists=on,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off,condition_pushdown_from_having=off,not_null_range_scan=off,hash_join_cardinality=off,cset_narrowing=off,sargable_casefold=off
|
||||||
select @@session.optimizer_switch;
|
select @@session.optimizer_switch;
|
||||||
@@session.optimizer_switch
|
@@session.optimizer_switch
|
||||||
index_merge=off,index_merge_union=on,index_merge_sort_union=off,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=on,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off,condition_pushdown_from_having=off,not_null_range_scan=off,hash_join_cardinality=off,cset_narrowing=off,sargable_casefold=off
|
index_merge=off,index_merge_union=on,index_merge_sort_union=off,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,duplicateweedout=off,materialization=on,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off,condition_pushdown_from_having=off,not_null_range_scan=off,hash_join_cardinality=off,cset_narrowing=off,sargable_casefold=off
|
||||||
set global optimizer_switch="index_merge_sort_union=on";
|
set global optimizer_switch="index_merge_sort_union=on";
|
||||||
set session optimizer_switch="index_merge=off";
|
set session optimizer_switch="index_merge=off";
|
||||||
select @@global.optimizer_switch;
|
select @@global.optimizer_switch;
|
||||||
@@global.optimizer_switch
|
@@global.optimizer_switch
|
||||||
index_merge=on,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=on,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off,condition_pushdown_from_having=off,not_null_range_scan=off,hash_join_cardinality=off,cset_narrowing=off,sargable_casefold=off
|
index_merge=on,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,duplicateweedout=off,materialization=off,in_to_exists=on,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off,condition_pushdown_from_having=off,not_null_range_scan=off,hash_join_cardinality=off,cset_narrowing=off,sargable_casefold=off
|
||||||
select @@session.optimizer_switch;
|
select @@session.optimizer_switch;
|
||||||
@@session.optimizer_switch
|
@@session.optimizer_switch
|
||||||
index_merge=off,index_merge_union=on,index_merge_sort_union=off,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=on,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off,condition_pushdown_from_having=off,not_null_range_scan=off,hash_join_cardinality=off,cset_narrowing=off,sargable_casefold=off
|
index_merge=off,index_merge_union=on,index_merge_sort_union=off,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,duplicateweedout=off,materialization=on,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off,condition_pushdown_from_having=off,not_null_range_scan=off,hash_join_cardinality=off,cset_narrowing=off,sargable_casefold=off
|
||||||
show global variables like 'optimizer_switch';
|
show global variables like 'optimizer_switch';
|
||||||
Variable_name Value
|
Variable_name Value
|
||||||
optimizer_switch index_merge=on,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=on,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off,condition_pushdown_from_having=off,not_null_range_scan=off,hash_join_cardinality=off,cset_narrowing=off,sargable_casefold=off
|
optimizer_switch index_merge=on,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,duplicateweedout=off,materialization=off,in_to_exists=on,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off,condition_pushdown_from_having=off,not_null_range_scan=off,hash_join_cardinality=off,cset_narrowing=off,sargable_casefold=off
|
||||||
show session variables like 'optimizer_switch';
|
show session variables like 'optimizer_switch';
|
||||||
Variable_name Value
|
Variable_name Value
|
||||||
optimizer_switch index_merge=off,index_merge_union=on,index_merge_sort_union=off,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=on,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off,condition_pushdown_from_having=off,not_null_range_scan=off,hash_join_cardinality=off,cset_narrowing=off,sargable_casefold=off
|
optimizer_switch index_merge=off,index_merge_union=on,index_merge_sort_union=off,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,duplicateweedout=off,materialization=on,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off,condition_pushdown_from_having=off,not_null_range_scan=off,hash_join_cardinality=off,cset_narrowing=off,sargable_casefold=off
|
||||||
select * from information_schema.global_variables where variable_name='optimizer_switch';
|
select * from information_schema.global_variables where variable_name='optimizer_switch';
|
||||||
VARIABLE_NAME VARIABLE_VALUE
|
VARIABLE_NAME VARIABLE_VALUE
|
||||||
OPTIMIZER_SWITCH index_merge=on,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=on,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off,condition_pushdown_from_having=off,not_null_range_scan=off,hash_join_cardinality=off,cset_narrowing=off,sargable_casefold=off
|
OPTIMIZER_SWITCH index_merge=on,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,duplicateweedout=off,materialization=off,in_to_exists=on,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off,condition_pushdown_from_having=off,not_null_range_scan=off,hash_join_cardinality=off,cset_narrowing=off,sargable_casefold=off
|
||||||
select * from information_schema.session_variables where variable_name='optimizer_switch';
|
select * from information_schema.session_variables where variable_name='optimizer_switch';
|
||||||
VARIABLE_NAME VARIABLE_VALUE
|
VARIABLE_NAME VARIABLE_VALUE
|
||||||
OPTIMIZER_SWITCH index_merge=off,index_merge_union=on,index_merge_sort_union=off,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=on,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off,condition_pushdown_from_having=off,not_null_range_scan=off,hash_join_cardinality=off,cset_narrowing=off,sargable_casefold=off
|
OPTIMIZER_SWITCH index_merge=off,index_merge_union=on,index_merge_sort_union=off,index_merge_intersection=on,index_merge_sort_intersection=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,duplicateweedout=off,materialization=on,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off,condition_pushdown_from_having=off,not_null_range_scan=off,hash_join_cardinality=off,cset_narrowing=off,sargable_casefold=off
|
||||||
set session optimizer_switch="default";
|
set session optimizer_switch="default";
|
||||||
select @@session.optimizer_switch;
|
select @@session.optimizer_switch;
|
||||||
@@session.optimizer_switch
|
@@session.optimizer_switch
|
||||||
index_merge=on,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=on,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off,condition_pushdown_from_having=off,not_null_range_scan=off,hash_join_cardinality=off,cset_narrowing=off,sargable_casefold=off
|
index_merge=on,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,duplicateweedout=off,materialization=off,in_to_exists=on,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off,condition_pushdown_from_having=off,not_null_range_scan=off,hash_join_cardinality=off,cset_narrowing=off,sargable_casefold=off
|
||||||
set optimizer_switch = replace(@@optimizer_switch, '=off', '=on');
|
set optimizer_switch = replace(@@optimizer_switch, '=off', '=on');
|
||||||
select @@optimizer_switch;
|
select @@optimizer_switch;
|
||||||
@@optimizer_switch
|
@@optimizer_switch
|
||||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=on,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=on,mrr_cost_based=on,mrr_sort_keys=on,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on,rowid_filter=on,condition_pushdown_from_having=on,not_null_range_scan=on,hash_join_cardinality=on,cset_narrowing=on,sargable_casefold=on
|
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=on,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,duplicateweedout=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=on,mrr_cost_based=on,mrr_sort_keys=on,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on,rowid_filter=on,condition_pushdown_from_having=on,not_null_range_scan=on,hash_join_cardinality=on,cset_narrowing=on,sargable_casefold=on
|
||||||
set global optimizer_switch=1.1;
|
set global optimizer_switch=1.1;
|
||||||
ERROR 42000: Incorrect argument type to variable 'optimizer_switch'
|
ERROR 42000: Incorrect argument type to variable 'optimizer_switch'
|
||||||
set global optimizer_switch=1e1;
|
set global optimizer_switch=1e1;
|
||||||
|
@@ -2649,7 +2649,7 @@ VARIABLE_COMMENT Fine-tune the optimizer behavior
|
|||||||
NUMERIC_MIN_VALUE NULL
|
NUMERIC_MIN_VALUE NULL
|
||||||
NUMERIC_MAX_VALUE NULL
|
NUMERIC_MAX_VALUE NULL
|
||||||
NUMERIC_BLOCK_SIZE NULL
|
NUMERIC_BLOCK_SIZE NULL
|
||||||
ENUM_VALUE_LIST index_merge,index_merge_union,index_merge_sort_union,index_merge_intersection,index_merge_sort_intersection,index_condition_pushdown,derived_merge,derived_with_keys,firstmatch,loosescan,materialization,in_to_exists,semijoin,partial_match_rowid_merge,partial_match_table_scan,subquery_cache,mrr,mrr_cost_based,mrr_sort_keys,outer_join_with_cache,semijoin_with_cache,join_cache_incremental,join_cache_hashed,join_cache_bka,optimize_join_buffer_size,table_elimination,extended_keys,exists_to_in,orderby_uses_equalities,condition_pushdown_for_derived,split_materialized,condition_pushdown_for_subquery,rowid_filter,condition_pushdown_from_having,not_null_range_scan,hash_join_cardinality,cset_narrowing,sargable_casefold,default
|
ENUM_VALUE_LIST index_merge,index_merge_union,index_merge_sort_union,index_merge_intersection,index_merge_sort_intersection,index_condition_pushdown,derived_merge,derived_with_keys,firstmatch,loosescan,duplicateweedout,materialization,in_to_exists,semijoin,partial_match_rowid_merge,partial_match_table_scan,subquery_cache,mrr,mrr_cost_based,mrr_sort_keys,outer_join_with_cache,semijoin_with_cache,join_cache_incremental,join_cache_hashed,join_cache_bka,optimize_join_buffer_size,table_elimination,extended_keys,exists_to_in,orderby_uses_equalities,condition_pushdown_for_derived,split_materialized,condition_pushdown_for_subquery,rowid_filter,condition_pushdown_from_having,not_null_range_scan,hash_join_cardinality,cset_narrowing,sargable_casefold,default
|
||||||
READ_ONLY NO
|
READ_ONLY NO
|
||||||
COMMAND_LINE_ARGUMENT REQUIRED
|
COMMAND_LINE_ARGUMENT REQUIRED
|
||||||
VARIABLE_NAME OPTIMIZER_TRACE
|
VARIABLE_NAME OPTIMIZER_TRACE
|
||||||
|
@@ -2869,7 +2869,7 @@ VARIABLE_COMMENT Fine-tune the optimizer behavior
|
|||||||
NUMERIC_MIN_VALUE NULL
|
NUMERIC_MIN_VALUE NULL
|
||||||
NUMERIC_MAX_VALUE NULL
|
NUMERIC_MAX_VALUE NULL
|
||||||
NUMERIC_BLOCK_SIZE NULL
|
NUMERIC_BLOCK_SIZE NULL
|
||||||
ENUM_VALUE_LIST index_merge,index_merge_union,index_merge_sort_union,index_merge_intersection,index_merge_sort_intersection,index_condition_pushdown,derived_merge,derived_with_keys,firstmatch,loosescan,materialization,in_to_exists,semijoin,partial_match_rowid_merge,partial_match_table_scan,subquery_cache,mrr,mrr_cost_based,mrr_sort_keys,outer_join_with_cache,semijoin_with_cache,join_cache_incremental,join_cache_hashed,join_cache_bka,optimize_join_buffer_size,table_elimination,extended_keys,exists_to_in,orderby_uses_equalities,condition_pushdown_for_derived,split_materialized,condition_pushdown_for_subquery,rowid_filter,condition_pushdown_from_having,not_null_range_scan,hash_join_cardinality,cset_narrowing,sargable_casefold,default
|
ENUM_VALUE_LIST index_merge,index_merge_union,index_merge_sort_union,index_merge_intersection,index_merge_sort_intersection,index_condition_pushdown,derived_merge,derived_with_keys,firstmatch,loosescan,duplicateweedout,materialization,in_to_exists,semijoin,partial_match_rowid_merge,partial_match_table_scan,subquery_cache,mrr,mrr_cost_based,mrr_sort_keys,outer_join_with_cache,semijoin_with_cache,join_cache_incremental,join_cache_hashed,join_cache_bka,optimize_join_buffer_size,table_elimination,extended_keys,exists_to_in,orderby_uses_equalities,condition_pushdown_for_derived,split_materialized,condition_pushdown_for_subquery,rowid_filter,condition_pushdown_from_having,not_null_range_scan,hash_join_cardinality,cset_narrowing,sargable_casefold,default
|
||||||
READ_ONLY NO
|
READ_ONLY NO
|
||||||
COMMAND_LINE_ARGUMENT REQUIRED
|
COMMAND_LINE_ARGUMENT REQUIRED
|
||||||
VARIABLE_NAME OPTIMIZER_TRACE
|
VARIABLE_NAME OPTIMIZER_TRACE
|
||||||
|
@@ -19,8 +19,8 @@ select * from information_schema.session_variables where variable_name='optimize
|
|||||||
#
|
#
|
||||||
# show that it's writable
|
# show that it's writable
|
||||||
#
|
#
|
||||||
set global optimizer_switch=2053;
|
set global optimizer_switch=4101;
|
||||||
set session optimizer_switch=1034;
|
set session optimizer_switch=2058;
|
||||||
select @@global.optimizer_switch;
|
select @@global.optimizer_switch;
|
||||||
select @@session.optimizer_switch;
|
select @@session.optimizer_switch;
|
||||||
set global optimizer_switch="index_merge_sort_union=on";
|
set global optimizer_switch="index_merge_sort_union=on";
|
||||||
|
@@ -6,6 +6,7 @@ condition_pushdown_from_having on
|
|||||||
cset_narrowing on
|
cset_narrowing on
|
||||||
derived_merge on
|
derived_merge on
|
||||||
derived_with_keys on
|
derived_with_keys on
|
||||||
|
duplicateweedout on
|
||||||
exists_to_in on
|
exists_to_in on
|
||||||
extended_keys on
|
extended_keys on
|
||||||
firstmatch on
|
firstmatch on
|
||||||
|
399
sql/opt_hints.cc
399
sql/opt_hints.cc
@@ -40,6 +40,8 @@ struct st_opt_hint_info opt_hint_info[]=
|
|||||||
{{STRING_WITH_LEN("NO_RANGE_OPTIMIZATION")}, true, false},
|
{{STRING_WITH_LEN("NO_RANGE_OPTIMIZATION")}, true, false},
|
||||||
{{STRING_WITH_LEN("QB_NAME")}, false, false},
|
{{STRING_WITH_LEN("QB_NAME")}, false, false},
|
||||||
{{STRING_WITH_LEN("MAX_EXECUTION_TIME")}, false, true},
|
{{STRING_WITH_LEN("MAX_EXECUTION_TIME")}, false, true},
|
||||||
|
{{STRING_WITH_LEN("SEMIJOIN")}, false, true},
|
||||||
|
{{STRING_WITH_LEN("SUBQUERY")}, false, true},
|
||||||
{null_clex_str, 0, 0}
|
{null_clex_str, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -99,7 +101,8 @@ void print_warn(THD *thd, uint err_code, opt_hints_enum hint_type,
|
|||||||
append_identifier(thd, &str, table_name_arg->str, table_name_arg->length);
|
append_identifier(thd, &str, table_name_arg->str, table_name_arg->length);
|
||||||
|
|
||||||
/* Append QB name */
|
/* Append QB name */
|
||||||
if (qb_name_arg && qb_name_arg->length > 0)
|
bool got_qb_name= qb_name_arg && qb_name_arg->length > 0;
|
||||||
|
if (got_qb_name)
|
||||||
{
|
{
|
||||||
if (hint_type != QB_NAME_HINT_ENUM)
|
if (hint_type != QB_NAME_HINT_ENUM)
|
||||||
{
|
{
|
||||||
@@ -122,7 +125,7 @@ void print_warn(THD *thd, uint err_code, opt_hints_enum hint_type,
|
|||||||
/* Append additional hint arguments if they exist */
|
/* Append additional hint arguments if they exist */
|
||||||
if (hint)
|
if (hint)
|
||||||
{
|
{
|
||||||
if (qb_name_arg || table_name_arg || key_name_arg)
|
if (got_qb_name || table_name_arg || key_name_arg)
|
||||||
str.append(' ');
|
str.append(' ');
|
||||||
|
|
||||||
hint->append_args(thd, &str);
|
hint->append_args(thd, &str);
|
||||||
@@ -351,7 +354,7 @@ Opt_hints_qb::Opt_hints_qb(Opt_hints *opt_hints_arg,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Opt_hints_table *Opt_hints_qb::adjust_table_hints(TABLE *table,
|
Opt_hints_table *Opt_hints_qb::adjust_hints_for_table(TABLE *table,
|
||||||
const Lex_ident_table &alias)
|
const Lex_ident_table &alias)
|
||||||
{
|
{
|
||||||
Opt_hints_table *tab= static_cast<Opt_hints_table *>(find_by_name(alias));
|
Opt_hints_table *tab= static_cast<Opt_hints_table *>(find_by_name(alias));
|
||||||
@@ -365,6 +368,46 @@ Opt_hints_table *Opt_hints_qb::adjust_table_hints(TABLE *table,
|
|||||||
return tab;
|
return tab;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Opt_hints_qb::semijoin_enabled(THD *thd) const
|
||||||
|
{
|
||||||
|
if (subquery_hint) // SUBQUERY hint disables semi-join
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (semijoin_hint)
|
||||||
|
{
|
||||||
|
// SEMIJOIN hint will always force semijoin regardless of optimizer_switch
|
||||||
|
if(get_switch(SEMIJOIN_HINT_ENUM))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// NO_SEMIJOIN hint. If strategy list is empty, do not use SEMIJOIN
|
||||||
|
if (semijoin_strategies_map == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Fall through: NO_SEMIJOIN w/ strategies neither turns SEMIJOIN off nor on
|
||||||
|
}
|
||||||
|
|
||||||
|
return optimizer_flag(thd, OPTIMIZER_SWITCH_SEMIJOIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint Opt_hints_qb::sj_enabled_strategies(uint opt_switches) const
|
||||||
|
{
|
||||||
|
// Hints override switches
|
||||||
|
if (semijoin_hint)
|
||||||
|
{
|
||||||
|
const uint strategies= semijoin_strategies_map;
|
||||||
|
if (get_switch(SEMIJOIN_HINT_ENUM)) // SEMIJOIN hint
|
||||||
|
return (strategies == 0) ? opt_switches : strategies;
|
||||||
|
|
||||||
|
// NO_SEMIJOIN hint. Hints and optimizer_switch both affect strategies
|
||||||
|
return ~strategies & opt_switches;
|
||||||
|
}
|
||||||
|
|
||||||
|
return opt_switches;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@brief
|
@brief
|
||||||
For each index IDX, put its hints into keyinfo_array[IDX]
|
For each index IDX, put its hints into keyinfo_array[IDX]
|
||||||
@@ -499,8 +542,16 @@ bool hint_table_state(const THD *thd, const TABLE *table,
|
|||||||
return fallback_value;
|
return fallback_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Resolve a parsed table level hint, i.e. set up proper Opt_hint_* structures
|
||||||
|
which will be used later during query preparation and optimization.
|
||||||
|
|
||||||
bool Optimizer_hint_parser::Table_level_hint::resolve(Parse_context *pc) const
|
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;
|
const Table_level_hint_type &table_level_hint_type= *this;
|
||||||
opt_hints_enum hint_type;
|
opt_hints_enum hint_type;
|
||||||
@@ -543,7 +594,7 @@ bool Optimizer_hint_parser::Table_level_hint::resolve(Parse_context *pc) const
|
|||||||
if (qb->set_switch(hint_state, hint_type, false))
|
if (qb->set_switch(hint_state, hint_type, false))
|
||||||
{
|
{
|
||||||
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
|
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
|
||||||
&qb_name_sys, NULL, NULL, (Parser::Hint*) NULL);
|
&qb_name_sys, nullptr, nullptr, (Parser::Hint*) nullptr);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -556,11 +607,12 @@ bool Optimizer_hint_parser::Table_level_hint::resolve(Parse_context *pc) const
|
|||||||
const Lex_ident_sys table_name_sys= table.to_ident_sys(pc->thd);
|
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);
|
Opt_hints_table *tab= get_table_hints(pc, table_name_sys, qb);
|
||||||
if (!tab)
|
if (!tab)
|
||||||
return true;
|
return false;
|
||||||
if (tab->set_switch(hint_state, hint_type, true))
|
if (tab->set_switch(hint_state, hint_type, true))
|
||||||
{
|
{
|
||||||
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
|
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
|
||||||
&qb_name_sys, &table_name_sys, NULL, (Parser::Hint*) NULL);
|
&qb_name_sys, &table_name_sys, nullptr,
|
||||||
|
(Parser::Hint*) nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -579,7 +631,7 @@ bool Optimizer_hint_parser::Table_level_hint::resolve(Parse_context *pc) const
|
|||||||
if (qb->set_switch(hint_state, hint_type, false))
|
if (qb->set_switch(hint_state, hint_type, false))
|
||||||
{
|
{
|
||||||
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
|
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
|
||||||
&null_ident_sys, NULL, NULL, (Parser::Hint*) NULL);
|
&null_ident_sys, nullptr, nullptr, (Parser::Hint*) nullptr);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -589,12 +641,12 @@ bool Optimizer_hint_parser::Table_level_hint::resolve(Parse_context *pc) const
|
|||||||
const Lex_ident_sys table_name_sys= table.to_ident_sys(pc->thd);
|
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);
|
Opt_hints_table *tab= get_table_hints(pc, table_name_sys, qb);
|
||||||
if (!tab)
|
if (!tab)
|
||||||
return true;
|
return false;
|
||||||
if (tab->set_switch(hint_state, hint_type, true))
|
if (tab->set_switch(hint_state, hint_type, true))
|
||||||
{
|
{
|
||||||
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
|
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
|
||||||
&null_ident_sys, &table_name_sys,
|
&null_ident_sys, &table_name_sys, nullptr,
|
||||||
NULL, (Parser::Hint*) NULL);
|
(Parser::Hint*) nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -610,18 +662,27 @@ bool Optimizer_hint_parser::Table_level_hint::resolve(Parse_context *pc) const
|
|||||||
to_ident_sys(pc->thd);
|
to_ident_sys(pc->thd);
|
||||||
Opt_hints_table *tab= get_table_hints(pc, table_name_sys, qb);
|
Opt_hints_table *tab= get_table_hints(pc, table_name_sys, qb);
|
||||||
if (!tab)
|
if (!tab)
|
||||||
return true;
|
return false;
|
||||||
if (tab->set_switch(hint_state, hint_type, true))
|
if (tab->set_switch(hint_state, hint_type, true))
|
||||||
{
|
{
|
||||||
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
|
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
|
||||||
&qb_name_sys, &table_name_sys, NULL, (Parser::Hint*) NULL);
|
&qb_name_sys, &table_name_sys, nullptr,
|
||||||
|
(Parser::Hint*) nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
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
|
bool Parser::Index_level_hint::resolve(Parse_context *pc) const
|
||||||
{
|
{
|
||||||
const Index_level_hint_type &index_level_hint_type= *this;
|
const Index_level_hint_type &index_level_hint_type= *this;
|
||||||
@@ -650,7 +711,7 @@ bool Parser::Index_level_hint::resolve(Parse_context *pc) const
|
|||||||
DBUG_ASSERT(0);
|
DBUG_ASSERT(0);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Hint_param_table_ext &table_ext= *this;
|
const Hint_param_table_ext &table_ext= *this;
|
||||||
const Lex_ident_sys qb_name_sys= table_ext.Query_block_name::
|
const Lex_ident_sys qb_name_sys= table_ext.Query_block_name::
|
||||||
to_ident_sys(pc->thd);
|
to_ident_sys(pc->thd);
|
||||||
@@ -662,14 +723,15 @@ bool Parser::Index_level_hint::resolve(Parse_context *pc) const
|
|||||||
|
|
||||||
Opt_hints_table *tab= get_table_hints(pc, table_name_sys, qb);
|
Opt_hints_table *tab= get_table_hints(pc, table_name_sys, qb);
|
||||||
if (!tab)
|
if (!tab)
|
||||||
return true;
|
return false;
|
||||||
|
|
||||||
if (is_empty()) // Table level hint
|
if (is_empty()) // Table level hint
|
||||||
{
|
{
|
||||||
if (tab->set_switch(hint_state, hint_type, false))
|
if (tab->set_switch(hint_state, hint_type, false))
|
||||||
{
|
{
|
||||||
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
|
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
|
||||||
&qb_name_sys, &table_name_sys, NULL, (Parser::Hint*) NULL);
|
&qb_name_sys, &table_name_sys, nullptr,
|
||||||
|
(Parser::Hint*) nullptr);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -689,14 +751,21 @@ bool Parser::Index_level_hint::resolve(Parse_context *pc) const
|
|||||||
{
|
{
|
||||||
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
|
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
|
||||||
&qb_name_sys, &table_name_sys, &index_name_sys,
|
&qb_name_sys, &table_name_sys, &index_name_sys,
|
||||||
(Parser::Hint*) NULL);
|
(Parser::Hint*) nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
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
|
bool Parser::Qb_name_hint::resolve(Parse_context *pc) const
|
||||||
{
|
{
|
||||||
Opt_hints_qb *qb= pc->select->opt_hints_qb;
|
Opt_hints_qb *qb= pc->select->opt_hints_qb;
|
||||||
@@ -709,7 +778,7 @@ bool Parser::Qb_name_hint::resolve(Parse_context *pc) const
|
|||||||
qb->get_parent()->find_by_name(qb_name_sys)) // Name is already used
|
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,
|
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, QB_NAME_HINT_ENUM, true,
|
||||||
&qb_name_sys, NULL, NULL, (Parser::Hint*) NULL);
|
&qb_name_sys, nullptr, nullptr, (Parser::Hint*) nullptr);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -717,6 +786,270 @@ bool Parser::Qb_name_hint::resolve(Parse_context *pc) const
|
|||||||
return false;
|
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
|
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
|
during the parsing phase, but at this stage some essential information is
|
||||||
@@ -765,7 +1098,7 @@ void Parser::Max_execution_time_hint::append_args(THD *thd, String *str) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ulong Parser::Max_execution_time_hint::get_milliseconds() const
|
ulonglong Parser::Max_execution_time_hint::get_milliseconds() const
|
||||||
{
|
{
|
||||||
const Unsigned_Number& hint_arg= *this;
|
const Unsigned_Number& hint_arg= *this;
|
||||||
return hint_arg.get_ulonglong().value();
|
return hint_arg.get_ulonglong().value();
|
||||||
@@ -774,9 +1107,16 @@ ulong Parser::Max_execution_time_hint::get_milliseconds() const
|
|||||||
|
|
||||||
bool Opt_hints_global::resolve(THD *thd)
|
bool Opt_hints_global::resolve(THD *thd)
|
||||||
{
|
{
|
||||||
if (!max_exec_time_hint || thd->lex->is_ps_or_view_context_analysis())
|
if (thd->lex->is_ps_or_view_context_analysis())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (!max_exec_time_hint)
|
||||||
|
{
|
||||||
|
/* No possible errors */
|
||||||
|
set_resolved();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
2nd step of MAX_EXECUTION_TIME() hint validation. Some checks were already
|
2nd step of MAX_EXECUTION_TIME() hint validation. Some checks were already
|
||||||
performed during the parsing stage (Max_execution_time_hint::resolve()),
|
performed during the parsing stage (Max_execution_time_hint::resolve()),
|
||||||
@@ -801,7 +1141,7 @@ bool Opt_hints_global::resolve(THD *thd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Optimizer_hint_parser::Hint_list::resolve(Parse_context *pc) const
|
bool Parser::Hint_list::resolve(Parse_context *pc) const
|
||||||
{
|
{
|
||||||
if (pc->thd->lex->create_view)
|
if (pc->thd->lex->create_view)
|
||||||
{
|
{
|
||||||
@@ -838,6 +1178,19 @@ bool Optimizer_hint_parser::Hint_list::resolve(Parse_context *pc) const
|
|||||||
if (max_hint.resolve(pc))
|
if (max_hint.resolve(pc))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
else if (const Semijoin_hint &sj_hint= hint)
|
||||||
|
{
|
||||||
|
if (sj_hint.resolve(pc))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (const Subquery_hint &subq_hint= hint)
|
||||||
|
{
|
||||||
|
if (subq_hint.resolve(pc))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DBUG_ASSERT(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@@ -38,8 +38,9 @@
|
|||||||
|
|
||||||
== Hint "adjustment" ==
|
== Hint "adjustment" ==
|
||||||
|
|
||||||
During Name Resolution, setup_tables() calls adjust_table_hints() for each
|
During Name Resolution, setup_tables() calls adjust_hints_for_table() for
|
||||||
table and sets TABLE_LIST::opt_hints_table to point to its Opt_hints_table.
|
each table and sets TABLE_LIST::opt_hints_table to point to its
|
||||||
|
Opt_hints_table.
|
||||||
|
|
||||||
== Hint hierarchy ==
|
== Hint hierarchy ==
|
||||||
|
|
||||||
@@ -76,6 +77,7 @@
|
|||||||
#include "mysqld_error.h"
|
#include "mysqld_error.h"
|
||||||
#include "opt_hints_parser.h"
|
#include "opt_hints_parser.h"
|
||||||
|
|
||||||
|
|
||||||
struct LEX;
|
struct LEX;
|
||||||
struct TABLE;
|
struct TABLE;
|
||||||
|
|
||||||
@@ -93,7 +95,9 @@ enum opt_hints_enum
|
|||||||
NO_RANGE_HINT_ENUM,
|
NO_RANGE_HINT_ENUM,
|
||||||
QB_NAME_HINT_ENUM,
|
QB_NAME_HINT_ENUM,
|
||||||
MAX_EXEC_TIME_HINT_ENUM,
|
MAX_EXEC_TIME_HINT_ENUM,
|
||||||
MAX_HINT_ENUM
|
SEMIJOIN_HINT_ENUM,
|
||||||
|
SUBQUERY_HINT_ENUM,
|
||||||
|
MAX_HINT_ENUM // This one must be the last in the list
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -201,10 +205,12 @@ private:
|
|||||||
*/
|
*/
|
||||||
Opt_hints *parent;
|
Opt_hints *parent;
|
||||||
|
|
||||||
Opt_hints_map hints_map; // Hint map
|
/* Bitmap describing switch-type (on/off) hints set at this scope */
|
||||||
|
Opt_hints_map hints_map;
|
||||||
|
|
||||||
/* Array of child objects. i.e. array of the lower level objects */
|
/* Array of child objects. i.e. array of the lower level objects */
|
||||||
Mem_root_array<Opt_hints*, true> child_array;
|
Mem_root_array<Opt_hints*, true> child_array;
|
||||||
|
|
||||||
/* true if hint is connected to the real object */
|
/* true if hint is connected to the real object */
|
||||||
bool resolved;
|
bool resolved;
|
||||||
/* Number of resolved children */
|
/* Number of resolved children */
|
||||||
@@ -256,6 +262,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool get_switch(opt_hints_enum type_arg) const;
|
bool get_switch(opt_hints_enum type_arg) const;
|
||||||
|
|
||||||
|
/* Collation for comparing the name of this hint */
|
||||||
virtual CHARSET_INFO *charset_info() const
|
virtual CHARSET_INFO *charset_info() const
|
||||||
{
|
{
|
||||||
return Lex_ident_column::charset_info();
|
return Lex_ident_column::charset_info();
|
||||||
@@ -339,7 +346,11 @@ protected:
|
|||||||
Override this function in descendants so that print_warn_unresolved()
|
Override this function in descendants so that print_warn_unresolved()
|
||||||
prints the proper warning text for table/index level unresolved hints
|
prints the proper warning text for table/index level unresolved hints
|
||||||
*/
|
*/
|
||||||
virtual uint get_warn_unresolved_code() const { return 0; }
|
virtual uint get_warn_unresolved_code() const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -390,7 +401,6 @@ class Opt_hints_qb : public Opt_hints
|
|||||||
char buff[32]; // Buffer to hold sys name
|
char buff[32]; // Buffer to hold sys name
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Opt_hints_qb(Opt_hints *opt_hints_arg,
|
Opt_hints_qb(Opt_hints *opt_hints_arg,
|
||||||
MEM_ROOT *mem_root_arg,
|
MEM_ROOT *mem_root_arg,
|
||||||
uint select_number_arg);
|
uint select_number_arg);
|
||||||
@@ -428,6 +438,23 @@ public:
|
|||||||
append_identifier(thd, str, &print_name);
|
append_identifier(thd, str, &print_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::function<void(THD*, String*)> get_args_printer() const override
|
||||||
|
{
|
||||||
|
using std::placeholders::_1;
|
||||||
|
using std::placeholders::_2;
|
||||||
|
if (semijoin_hint)
|
||||||
|
{
|
||||||
|
return std::bind(&Parser::Semijoin_hint::append_args, semijoin_hint,
|
||||||
|
_1, _2);
|
||||||
|
}
|
||||||
|
else if (subquery_hint)
|
||||||
|
{
|
||||||
|
return std::bind(&Parser::Subquery_hint::append_args, subquery_hint,
|
||||||
|
_1, _2);
|
||||||
|
}
|
||||||
|
return [](THD*, String*) {};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Function finds Opt_hints_table object corresponding to
|
Function finds Opt_hints_table object corresponding to
|
||||||
table alias in the query block and attaches corresponding
|
table alias in the query block and attaches corresponding
|
||||||
@@ -439,8 +466,46 @@ public:
|
|||||||
@return pointer Opt_hints_table object if this object is found,
|
@return pointer Opt_hints_table object if this object is found,
|
||||||
NULL otherwise.
|
NULL otherwise.
|
||||||
*/
|
*/
|
||||||
Opt_hints_table *adjust_table_hints(TABLE *table,
|
Opt_hints_table *adjust_hints_for_table(TABLE *table,
|
||||||
const Lex_ident_table &alias);
|
const Lex_ident_table &alias);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns whether semi-join is enabled for this query block
|
||||||
|
|
||||||
|
A SEMIJOIN hint will force semi-join regardless of optimizer_switch settings.
|
||||||
|
A NO_SEMIJOIN hint will only turn off semi-join if the variant with no
|
||||||
|
strategies is used.
|
||||||
|
A SUBQUERY hint will turn off semi-join.
|
||||||
|
If there is no SEMIJOIN/SUBQUERY hint, optimizer_switch setting determines
|
||||||
|
whether SEMIJOIN is used.
|
||||||
|
|
||||||
|
@param thd Pointer to THD object for session.
|
||||||
|
Used to access optimizer_switch
|
||||||
|
|
||||||
|
@return true if semijoin is enabled
|
||||||
|
*/
|
||||||
|
bool semijoin_enabled(THD *thd) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns bit mask of which semi-join strategies are enabled for this query
|
||||||
|
block.
|
||||||
|
|
||||||
|
@param opt_switches Bit map of strategies enabled by optimizer_switch
|
||||||
|
|
||||||
|
@return Bit mask of strategies that are enabled
|
||||||
|
*/
|
||||||
|
uint sj_enabled_strategies(uint opt_switches) const;
|
||||||
|
|
||||||
|
const Parser::Semijoin_hint* semijoin_hint= nullptr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Bitmap of strategies listed in the SEMIJOIN/NO_SEMIJOIN hint body, e.g.
|
||||||
|
FIRSTMATCH | LOOSESCAN
|
||||||
|
*/
|
||||||
|
uint semijoin_strategies_map= 0;
|
||||||
|
|
||||||
|
const Parser::Subquery_hint *subquery_hint= nullptr;
|
||||||
|
uint subquery_strategy= SUBS_NOT_TRANSFORMED;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -465,7 +530,6 @@ public:
|
|||||||
return Lex_ident_table::charset_info();
|
return Lex_ident_table::charset_info();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Append table name.
|
Append table name.
|
||||||
|
|
||||||
@@ -477,6 +541,7 @@ public:
|
|||||||
append_identifier(thd, str, &name);
|
append_identifier(thd, str, &name);
|
||||||
get_parent()->append_name(thd, str);
|
get_parent()->append_name(thd, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Function sets correlation between key hint objects and
|
Function sets correlation between key hint objects and
|
||||||
appropriate KEY structures.
|
appropriate KEY structures.
|
||||||
|
@@ -57,6 +57,37 @@ Optimizer_hint_tokenizer::find_keyword(const LEX_CSTRING &str)
|
|||||||
return TokenID::keyword_QB_NAME;
|
return TokenID::keyword_QB_NAME;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 8:
|
||||||
|
if ("SEMIJOIN"_Lex_ident_column.streq(str))
|
||||||
|
return TokenID::keyword_SEMIJOIN;
|
||||||
|
else if ("SUBQUERY"_Lex_ident_column.streq(str))
|
||||||
|
return TokenID::keyword_SUBQUERY;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 9:
|
||||||
|
if ("LOOSESCAN"_Lex_ident_column.streq(str))
|
||||||
|
return TokenID::keyword_LOOSESCAN;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 10:
|
||||||
|
if ("FIRSTMATCH"_Lex_ident_column.streq(str))
|
||||||
|
return TokenID::keyword_FIRSTMATCH;
|
||||||
|
else if ("INTOEXISTS"_Lex_ident_column.streq(str))
|
||||||
|
return TokenID::keyword_INTOEXISTS;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 11:
|
||||||
|
if ("NO_SEMIJOIN"_Lex_ident_column.streq(str))
|
||||||
|
return TokenID::keyword_NO_SEMIJOIN;
|
||||||
|
else if ("DUPSWEEDOUT"_Lex_ident_column.streq(str))
|
||||||
|
return TokenID::keyword_DUPSWEEDOUT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 15:
|
||||||
|
if ("MATERIALIZATION"_Lex_ident_column.streq(str))
|
||||||
|
return TokenID::keyword_MATERIALIZATION;
|
||||||
|
break;
|
||||||
|
|
||||||
case 18:
|
case 18:
|
||||||
if ("MAX_EXECUTION_TIME"_Lex_ident_column.streq(str))
|
if ("MAX_EXECUTION_TIME"_Lex_ident_column.streq(str))
|
||||||
return TokenID::keyword_MAX_EXECUTION_TIME;
|
return TokenID::keyword_MAX_EXECUTION_TIME;
|
||||||
@@ -220,3 +251,16 @@ Optimizer_hint_parser::
|
|||||||
*pe= std::move(elem);
|
*pe= std::move(elem);
|
||||||
return push_back(pe, p->m_thd->mem_root);
|
return push_back(pe, p->m_thd->mem_root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Optimizer_hint_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)
|
||||||
|
return true;
|
||||||
|
*pe= std::move(elem);
|
||||||
|
return push_back(pe, p->m_thd->mem_root);
|
||||||
|
}
|
||||||
|
@@ -26,6 +26,7 @@
|
|||||||
#include "simple_parser.h"
|
#include "simple_parser.h"
|
||||||
|
|
||||||
class st_select_lex;
|
class st_select_lex;
|
||||||
|
class Opt_hints_qb;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Environment data for the name resolution phase
|
Environment data for the name resolution phase
|
||||||
@@ -74,6 +75,14 @@ public:
|
|||||||
keyword_MRR,
|
keyword_MRR,
|
||||||
keyword_QB_NAME,
|
keyword_QB_NAME,
|
||||||
keyword_MAX_EXECUTION_TIME,
|
keyword_MAX_EXECUTION_TIME,
|
||||||
|
keyword_SEMIJOIN,
|
||||||
|
keyword_NO_SEMIJOIN,
|
||||||
|
keyword_SUBQUERY,
|
||||||
|
keyword_MATERIALIZATION,
|
||||||
|
keyword_FIRSTMATCH,
|
||||||
|
keyword_LOOSESCAN,
|
||||||
|
keyword_DUPSWEEDOUT,
|
||||||
|
keyword_INTOEXISTS,
|
||||||
|
|
||||||
// Other token types
|
// Other token types
|
||||||
tIDENT,
|
tIDENT,
|
||||||
@@ -250,6 +259,12 @@ private:
|
|||||||
using TOKEN::TOKEN;
|
using TOKEN::TOKEN;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Keyword_SUBQUERY: public TOKEN<Parser, TokenID::keyword_SUBQUERY>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using TOKEN::TOKEN;
|
||||||
|
};
|
||||||
|
|
||||||
class Identifier: public TOKEN<Parser, TokenID::tIDENT>
|
class Identifier: public TOKEN<Parser, TokenID::tIDENT>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -344,10 +359,8 @@ private:
|
|||||||
using TokenChoice::TokenChoice;
|
using TokenChoice::TokenChoice;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Identifiers of various kinds
|
// Identifiers of various kinds
|
||||||
|
|
||||||
|
|
||||||
// query_block_name ::= identifier
|
// query_block_name ::= identifier
|
||||||
class Query_block_name: public Identifier
|
class Query_block_name: public Identifier
|
||||||
{
|
{
|
||||||
@@ -599,25 +612,230 @@ public:
|
|||||||
|
|
||||||
bool resolve(Parse_context *pc) const;
|
bool resolve(Parse_context *pc) const;
|
||||||
void append_args(THD *thd, String *str) const;
|
void append_args(THD *thd, String *str) const;
|
||||||
ulong get_milliseconds() const;
|
ulonglong get_milliseconds() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// semijoin_hint_type ::= SEMIJOIN | NO_SEMIJOIN
|
||||||
|
class Semijoin_hint_type_cond
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static bool allowed_token_id(TokenID id)
|
||||||
|
{
|
||||||
|
return id == TokenID::keyword_SEMIJOIN ||
|
||||||
|
id == TokenID::keyword_NO_SEMIJOIN;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
class Semijoin_hint_type: public TokenChoice<Parser,
|
||||||
|
Semijoin_hint_type_cond>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using TokenChoice::TokenChoice;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// semijoin_strategy ::= MATERIALIZATION | FIRSTMATCH | LOOSESCAN | DUPSWEEDOUT
|
||||||
|
class Semijoin_strategy_cond
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static bool allowed_token_id(TokenID id)
|
||||||
|
{
|
||||||
|
return id == TokenID::keyword_MATERIALIZATION ||
|
||||||
|
id == TokenID::keyword_FIRSTMATCH ||
|
||||||
|
id == TokenID::keyword_LOOSESCAN ||
|
||||||
|
id == TokenID::keyword_DUPSWEEDOUT;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Semijoin_strategy: public TokenChoice<Parser, Semijoin_strategy_cond>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using TokenChoice::TokenChoice;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
strategy_list ::= strategy_name [ {, strategy_name }... ]
|
||||||
|
opt_strategy_list ::= [ strategy_list ]
|
||||||
|
*/
|
||||||
|
class Semijoin_strategy_list_container: public List<Semijoin_strategy>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Semijoin_strategy_list_container()
|
||||||
|
{ }
|
||||||
|
bool add(Optimizer_hint_parser *p, Semijoin_strategy &&strategy);
|
||||||
|
size_t count() const { return elements; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class Opt_sj_strategy_list: public LIST<Parser,
|
||||||
|
Semijoin_strategy_list_container,
|
||||||
|
Semijoin_strategy, TokenID::tCOMMA, 0>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using LIST::LIST;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Hint_param_opt_sj_strategy_list: public LIST<Parser,
|
||||||
|
Semijoin_strategy_list_container,
|
||||||
|
Semijoin_strategy, TokenID::tCOMMA, 0>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using LIST::LIST;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
at_query_block_name_opt_strategies_list ::=
|
||||||
|
@ query_block_name opt_strategies_list
|
||||||
|
*/
|
||||||
|
class At_query_block_name_opt_strategy_list: public AND2<
|
||||||
|
Parser,
|
||||||
|
At_query_block_name,
|
||||||
|
Opt_sj_strategy_list>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using AND2::AND2;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
semijoin_hint_body: @ query_block_name opt_sj_strategy_list
|
||||||
|
| opt_sj_strategy_list
|
||||||
|
*/
|
||||||
|
class Semijoin_hint_body: public OR2<Parser,
|
||||||
|
At_query_block_name_opt_strategy_list,
|
||||||
|
Hint_param_opt_sj_strategy_list>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using OR2::OR2;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*
|
||||||
|
semijoin_hint ::= semijoin_hint_type ( semijoin_hint_body )
|
||||||
|
*/
|
||||||
|
class Semijoin_hint: public AND4<Parser,
|
||||||
|
Semijoin_hint_type,
|
||||||
|
LParen,
|
||||||
|
Semijoin_hint_body,
|
||||||
|
RParen>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using AND4::AND4;
|
||||||
|
|
||||||
|
bool resolve(Parse_context *pc) const;
|
||||||
|
void append_args(THD *thd, String *str) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Opt_hints_qb* resolve_for_qb_name(Parse_context *pc, bool hint_state,
|
||||||
|
const Lex_ident_sys *qb_name) const;
|
||||||
|
void fill_strategies_map(Opt_hints_qb *qb) const;
|
||||||
|
void add_strategy_to_map(TokenID token_id, Opt_hints_qb *qb) const;
|
||||||
|
void append_strategy_name(TokenID token_id, String *str) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
// subquery_strategy ::= MATERIALIZATION | INTOEXISTS
|
||||||
|
class Subquery_strategy_cond
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static bool allowed_token_id(TokenID id)
|
||||||
|
{
|
||||||
|
return id == TokenID::keyword_MATERIALIZATION ||
|
||||||
|
id == TokenID::keyword_INTOEXISTS;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Subquery_strategy: public TokenChoice<Parser, Subquery_strategy_cond>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using TokenChoice::TokenChoice;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Hint_param_subquery_strategy: public TokenChoice<Parser,
|
||||||
|
Subquery_strategy_cond>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using TokenChoice::TokenChoice;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
at_query_block_name_subquery_strategy ::=
|
||||||
|
@ query_block_name subquery_strategy
|
||||||
|
*/
|
||||||
|
class At_query_block_name_subquery_strategy: public AND2<
|
||||||
|
Parser,
|
||||||
|
At_query_block_name,
|
||||||
|
Subquery_strategy>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using AND2::AND2;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
subquery_hint_body: @ query_block_name subquery_strategy
|
||||||
|
| subquery_strategy
|
||||||
|
*/
|
||||||
|
class Subquery_hint_body: public OR2<Parser,
|
||||||
|
At_query_block_name_subquery_strategy,
|
||||||
|
Hint_param_subquery_strategy>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using OR2::OR2;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
// subquery_hint ::= SUBQUERY( subquery_hint_body )
|
||||||
|
class Subquery_hint: public AND4<Parser,
|
||||||
|
Keyword_SUBQUERY,
|
||||||
|
LParen,
|
||||||
|
Subquery_hint_body,
|
||||||
|
RParen>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using AND4::AND4;
|
||||||
|
|
||||||
|
bool resolve(Parse_context *pc) const;
|
||||||
|
void append_args(THD *thd, String *str) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void set_subquery_strategy(TokenID token_id, Opt_hints_qb *qb) const;
|
||||||
|
Opt_hints_qb* resolve_for_qb_name(Parse_context *pc, TokenID token_id,
|
||||||
|
const Lex_ident_sys *qb_name) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
hint ::= index_level_hint
|
hint ::= index_level_hint
|
||||||
| table_level_hint
|
| table_level_hint
|
||||||
| qb_name_hint
|
| qb_name_hint
|
||||||
| statement_level_hint
|
| max_execution_time_hint
|
||||||
|
| semijoin_hint
|
||||||
|
| subquery_hint
|
||||||
*/
|
*/
|
||||||
class Hint: public OR4<Parser,
|
class Hint: public OR6<Parser,
|
||||||
Index_level_hint,
|
Index_level_hint,
|
||||||
Table_level_hint,
|
Table_level_hint,
|
||||||
Qb_name_hint,
|
Qb_name_hint,
|
||||||
Max_execution_time_hint>
|
Max_execution_time_hint,
|
||||||
|
Semijoin_hint,
|
||||||
|
Subquery_hint>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using OR4::OR4;
|
using OR6::OR6;
|
||||||
};
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Append additional hint arguments to the printed string.
|
||||||
|
Implement this method in Hint specifications if needed:
|
||||||
|
Table_level_hint, Semijoin_hint, etc
|
||||||
|
|
||||||
|
@param thd Pointer to THD object
|
||||||
|
@param str Pointer to String object
|
||||||
|
*/
|
||||||
|
void append_args(THD *thd, String *str) const {}
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// hint_list ::= hint [ hint... ]
|
// hint_list ::= hint [ hint... ]
|
||||||
@@ -630,6 +848,7 @@ private:
|
|||||||
size_t count() const { return elements; }
|
size_t count() const { return elements; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class Hint_list: public LIST<Parser, Hint_list_container,
|
class Hint_list: public LIST<Parser, Hint_list_container,
|
||||||
Hint, TokenID::tNULL/*not separated list*/, 1>
|
Hint, TokenID::tNULL/*not separated list*/, 1>
|
||||||
{
|
{
|
||||||
@@ -649,12 +868,11 @@ public:
|
|||||||
public:
|
public:
|
||||||
using AND2::AND2;
|
using AND2::AND2;
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This wrapper class is needed to use a forward declaration in sql_lex.h
|
These wrapper class is needed to use a forward declarations in sql_lex.h
|
||||||
instead of including the entire opt_hints_parser.h.
|
instead of including the entire opt_hints_parser.h.
|
||||||
(forward declarations of qualified nested classes are not possible in C++)
|
(forward declarations of qualified nested classes are not possible in C++)
|
||||||
*/
|
*/
|
||||||
@@ -664,5 +882,4 @@ public:
|
|||||||
using Hints::Hints;
|
using Hints::Hints;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif // OPT_HINTS_PARSER
|
#endif // OPT_HINTS_PARSER
|
||||||
|
@@ -466,6 +466,7 @@ enum_nested_loop_state
|
|||||||
end_sj_materialize(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
|
end_sj_materialize(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Check if Materialization strategy is allowed for given subquery predicate.
|
Check if Materialization strategy is allowed for given subquery predicate.
|
||||||
|
|
||||||
@@ -485,7 +486,7 @@ bool is_materialization_applicable(THD *thd, Item_in_subselect *in_subs,
|
|||||||
/*
|
/*
|
||||||
Check if the subquery predicate can be executed via materialization.
|
Check if the subquery predicate can be executed via materialization.
|
||||||
The required conditions are:
|
The required conditions are:
|
||||||
0. The materialization optimizer switch was set.
|
0. The materialization optimizer switch/hint was set.
|
||||||
1. Subquery is a single SELECT (not a UNION).
|
1. Subquery is a single SELECT (not a UNION).
|
||||||
TODO: this is a limitation that can be fixed
|
TODO: this is a limitation that can be fixed
|
||||||
2. Subquery is not a table-less query. In this case there is no
|
2. Subquery is not a table-less query. In this case there is no
|
||||||
@@ -514,7 +515,8 @@ bool is_materialization_applicable(THD *thd, Item_in_subselect *in_subs,
|
|||||||
select_lex->sj_subselects list to be populated for every EXECUTE.
|
select_lex->sj_subselects list to be populated for every EXECUTE.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
if (optimizer_flag(thd, OPTIMIZER_SWITCH_MATERIALIZATION) && // 0
|
uint strategies_allowed= child_select->subquery_strategies_allowed(thd);
|
||||||
|
if ((strategies_allowed & SUBS_MATERIALIZATION) && // 0
|
||||||
!child_select->is_part_of_union() && // 1
|
!child_select->is_part_of_union() && // 1
|
||||||
parent_unit->first_select()->leaf_tables.elements && // 2
|
parent_unit->first_select()->leaf_tables.elements && // 2
|
||||||
child_select->outer_select() &&
|
child_select->outer_select() &&
|
||||||
@@ -740,7 +742,7 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
|
|||||||
yet. They are checked later in convert_join_subqueries_to_semijoins(),
|
yet. They are checked later in convert_join_subqueries_to_semijoins(),
|
||||||
look for calls to block_conversion_to_sj().
|
look for calls to block_conversion_to_sj().
|
||||||
*/
|
*/
|
||||||
if (optimizer_flag(thd, OPTIMIZER_SWITCH_SEMIJOIN) &&
|
if (select_lex->semijoin_enabled(thd) &&
|
||||||
in_subs && // 1
|
in_subs && // 1
|
||||||
!select_lex->is_part_of_union() && // 2
|
!select_lex->is_part_of_union() && // 2
|
||||||
!select_lex->group_list.elements && !join->order && // 3
|
!select_lex->group_list.elements && !join->order && // 3
|
||||||
@@ -816,7 +818,7 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
|
|||||||
with jtbm strategy
|
with jtbm strategy
|
||||||
*/
|
*/
|
||||||
if (in_subs->emb_on_expr_nest == NO_JOIN_NEST &&
|
if (in_subs->emb_on_expr_nest == NO_JOIN_NEST &&
|
||||||
optimizer_flag(thd, OPTIMIZER_SWITCH_SEMIJOIN))
|
select_lex->semijoin_enabled(thd))
|
||||||
{
|
{
|
||||||
in_subs->is_flattenable_semijoin= FALSE;
|
in_subs->is_flattenable_semijoin= FALSE;
|
||||||
if (!in_subs->is_registered_semijoin)
|
if (!in_subs->is_registered_semijoin)
|
||||||
@@ -834,11 +836,11 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
IN-TO-EXISTS is the only universal strategy. Choose it if the user
|
IN-TO-EXISTS is the only universal strategy. Choose it if the user
|
||||||
allowed it via an optimizer switch, or if materialization is not
|
allowed it via an optimizer switch/hint, or if materialization is not
|
||||||
possible.
|
possible.
|
||||||
*/
|
*/
|
||||||
if (optimizer_flag(thd, OPTIMIZER_SWITCH_IN_TO_EXISTS) ||
|
uint strategies_allowed= select_lex->subquery_strategies_allowed(thd);
|
||||||
!in_subs->has_strategy())
|
if (strategies_allowed & SUBS_IN_TO_EXISTS || !in_subs->has_strategy())
|
||||||
in_subs->add_strategy(SUBS_IN_TO_EXISTS);
|
in_subs->add_strategy(SUBS_IN_TO_EXISTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2559,11 +2561,11 @@ bool optimize_semijoin_nests(JOIN *join, table_map all_table_map)
|
|||||||
|
|
||||||
sj_nest->sj_mat_info= NULL;
|
sj_nest->sj_mat_info= NULL;
|
||||||
/*
|
/*
|
||||||
The statement may have been executed with 'semijoin=on' earlier.
|
The statement may have been executed as a semijoin earlier.
|
||||||
We need to verify that 'semijoin=on' still holds.
|
We need to verify that semijoin materialization is still allowed.
|
||||||
*/
|
*/
|
||||||
if (optimizer_flag(join->thd, OPTIMIZER_SWITCH_SEMIJOIN) &&
|
if (sj_nest->nested_join->sj_enabled_strategies &
|
||||||
optimizer_flag(join->thd, OPTIMIZER_SWITCH_MATERIALIZATION))
|
OPTIMIZER_SWITCH_MATERIALIZATION)
|
||||||
{
|
{
|
||||||
if ((sj_nest->sj_inner_tables & ~join->const_table_map) && /* not everything was pulled out */
|
if ((sj_nest->sj_inner_tables & ~join->const_table_map) && /* not everything was pulled out */
|
||||||
!sj_nest->sj_subq_pred->is_correlated &&
|
!sj_nest->sj_subq_pred->is_correlated &&
|
||||||
@@ -3050,10 +3052,20 @@ void optimize_semi_joins(JOIN *join, table_map remaining_tables, uint idx,
|
|||||||
(dusp_producing_tables & handled_fanout is true), then
|
(dusp_producing_tables & handled_fanout is true), then
|
||||||
*current_read_time is updated and the cost for the next
|
*current_read_time is updated and the cost for the next
|
||||||
strategy can be smaller than *current_read_time.
|
strategy can be smaller than *current_read_time.
|
||||||
|
|
||||||
|
The strategy may be disabled by an optimizer switch or a hint,
|
||||||
|
which is checked at (1). Currently, this is applicable only to
|
||||||
|
Duplicate Weedout since other disabled strategies will will be
|
||||||
|
cut off earlier and will not make it here. However, since
|
||||||
|
Duplicate Weedout serves as the default fallback strategy, it is
|
||||||
|
chosen even when disabled, provided no other viable alternatives
|
||||||
|
are available.
|
||||||
*/
|
*/
|
||||||
if ((dups_producing_tables & handled_fanout) ||
|
if (((dups_producing_tables & handled_fanout) ||
|
||||||
(read_time + COST_EPS < *current_read_time &&
|
(read_time + COST_EPS < *current_read_time &&
|
||||||
!(handled_fanout & pos->inner_tables_handled_with_other_sjs)))
|
!(handled_fanout & pos->inner_tables_handled_with_other_sjs))) &&
|
||||||
|
(!(*strategy)->is_disabled() ||
|
||||||
|
pos->sj_strategy == SJ_OPT_NONE)) // (1)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(pos->sj_strategy != sj_strategy);
|
DBUG_ASSERT(pos->sj_strategy != sj_strategy);
|
||||||
/*
|
/*
|
||||||
@@ -3481,7 +3493,8 @@ bool Firstmatch_picker::check_qep(JOIN *join,
|
|||||||
POSITION *loose_scan_pos)
|
POSITION *loose_scan_pos)
|
||||||
{
|
{
|
||||||
if (new_join_tab->emb_sj_nest &&
|
if (new_join_tab->emb_sj_nest &&
|
||||||
optimizer_flag(join->thd, OPTIMIZER_SWITCH_FIRSTMATCH) &&
|
(new_join_tab->emb_sj_nest->nested_join->sj_enabled_strategies &
|
||||||
|
OPTIMIZER_SWITCH_FIRSTMATCH) &&
|
||||||
!join->outer_join)
|
!join->outer_join)
|
||||||
{
|
{
|
||||||
const table_map outer_corr_tables=
|
const table_map outer_corr_tables=
|
||||||
@@ -3725,10 +3738,22 @@ bool Duplicate_weedout_picker::check_qep(JOIN *join,
|
|||||||
POSITION *p= join->positions + j;
|
POSITION *p= join->positions + j;
|
||||||
dups_cost= COST_ADD(dups_cost, p->read_time);
|
dups_cost= COST_ADD(dups_cost, p->read_time);
|
||||||
|
|
||||||
if (p->table->emb_sj_nest)
|
TABLE_LIST *emb_sj_nest= p->table->emb_sj_nest;
|
||||||
|
if (emb_sj_nest)
|
||||||
{
|
{
|
||||||
sj_inner_fanout= COST_MULT(sj_inner_fanout, p->records_out);
|
sj_inner_fanout= COST_MULT(sj_inner_fanout, p->records_out);
|
||||||
dups_removed_fanout |= p->table->table->map;
|
dups_removed_fanout |= p->table->table->map;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Duplicate Weedout is the default fallback strategy. It is used when
|
||||||
|
all other strategies are disabled by either an optimizer switch or
|
||||||
|
a hint. So, mark it as disabled for when there are other enabled
|
||||||
|
strategies to choose from
|
||||||
|
*/
|
||||||
|
disabled |=
|
||||||
|
emb_sj_nest->nested_join->sj_enabled_strategies != 0 && // (1)
|
||||||
|
!(emb_sj_nest->nested_join->sj_enabled_strategies &
|
||||||
|
OPTIMIZER_SWITCH_DUPSWEEDOUT);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -3936,7 +3961,9 @@ at_sjmat_pos(const JOIN *join, table_map remaining_tables, const JOIN_TAB *tab,
|
|||||||
TABLE_LIST *emb_sj_nest= tab->emb_sj_nest;
|
TABLE_LIST *emb_sj_nest= tab->emb_sj_nest;
|
||||||
table_map suffix= remaining_tables & ~tab->table->map;
|
table_map suffix= remaining_tables & ~tab->table->map;
|
||||||
if (emb_sj_nest && emb_sj_nest->sj_mat_info &&
|
if (emb_sj_nest && emb_sj_nest->sj_mat_info &&
|
||||||
!(suffix & emb_sj_nest->sj_inner_tables))
|
!(suffix & emb_sj_nest->sj_inner_tables) &&
|
||||||
|
(emb_sj_nest->nested_join->sj_enabled_strategies &
|
||||||
|
OPTIMIZER_SWITCH_MATERIALIZATION))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Walk back and check if all immediately preceding tables are from
|
Walk back and check if all immediately preceding tables are from
|
||||||
|
@@ -117,6 +117,7 @@ public:
|
|||||||
bound
|
bound
|
||||||
5. But some of the IN-equalities aren't (so this can't be handled by
|
5. But some of the IN-equalities aren't (so this can't be handled by
|
||||||
FirstMatch strategy)
|
FirstMatch strategy)
|
||||||
|
6. LooseScan strategy is enabled for this SJ nest
|
||||||
*/
|
*/
|
||||||
best_loose_scan_cost= DBL_MAX;
|
best_loose_scan_cost= DBL_MAX;
|
||||||
if (!join->emb_sjm_nest && s->emb_sj_nest && // (1)
|
if (!join->emb_sjm_nest && s->emb_sj_nest && // (1)
|
||||||
@@ -127,7 +128,8 @@ public:
|
|||||||
!(remaining_tables &
|
!(remaining_tables &
|
||||||
s->emb_sj_nest->nested_join->sj_corr_tables) && // (4)
|
s->emb_sj_nest->nested_join->sj_corr_tables) && // (4)
|
||||||
remaining_tables & s->emb_sj_nest->nested_join->sj_depends_on &&// (5)
|
remaining_tables & s->emb_sj_nest->nested_join->sj_depends_on &&// (5)
|
||||||
optimizer_flag(join->thd, OPTIMIZER_SWITCH_LOOSE_SCAN))
|
(s->emb_sj_nest->nested_join->sj_enabled_strategies & // (6)
|
||||||
|
OPTIMIZER_SWITCH_LOOSE_SCAN))
|
||||||
{
|
{
|
||||||
/* This table is an LooseScan scan candidate */
|
/* This table is an LooseScan scan candidate */
|
||||||
bound_sj_equalities= get_bound_sj_equalities(s->emb_sj_nest,
|
bound_sj_equalities= get_bound_sj_equalities(s->emb_sj_nest,
|
||||||
|
@@ -478,10 +478,9 @@ protected:
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
A rule consisting of a choice of four rules:
|
A rule consisting of a choice of four rules:
|
||||||
rule ::= rule1 | rule2 | rule3 | rule4
|
rule ::= rule1 | rule2 | rule3 | rule4
|
||||||
|
For the case when the four branches have incompatible storage
|
||||||
For the case when the three branches have incompatible storage
|
|
||||||
*/
|
*/
|
||||||
template<class PARSER, class A, class B, class C, class D>
|
template<class PARSER, class A, class B, class C, class D>
|
||||||
class OR4: public A, public B, public C, public D
|
class OR4: public A, public B, public C, public D
|
||||||
@@ -519,9 +518,57 @@ protected:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
A rule consisting of a choice of six rules:
|
||||||
|
rule ::= rule1 | rule2 | rule3 | rule4 | rule5 | rule6
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OR6()
|
||||||
|
{ }
|
||||||
|
OR6(OR6 &&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)))
|
||||||
|
{ }
|
||||||
|
OR6 & operator=(OR6 &&rhs)
|
||||||
|
{
|
||||||
|
A::operator=(std::move(static_cast<A&&>(rhs)));
|
||||||
|
B::operator=(std::move(static_cast<B&&>(rhs)));
|
||||||
|
C::operator=(std::move(static_cast<C&&>(rhs)));
|
||||||
|
D::operator=(std::move(static_cast<D&&>(rhs)));
|
||||||
|
E::operator=(std::move(static_cast<E&&>(rhs)));
|
||||||
|
F::operator=(std::move(static_cast<F&&>(rhs)));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
OR6(PARSER *p)
|
||||||
|
:A(p),
|
||||||
|
B(A::operator bool() ? B() : B(p)),
|
||||||
|
C(A::operator bool() || B::operator bool() ? C() : C(p)),
|
||||||
|
D(A::operator bool() || B::operator bool() || C::operator bool() ?
|
||||||
|
D() : D(p)),
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
A list with at least MIN_COUNT elements (typically 0 or 1),
|
A list with at least MIN_COUNT elements (typlically 0 or 1),
|
||||||
with or without a token separator between elements:
|
with or without a token separator between elements:
|
||||||
|
|
||||||
list ::= element [ {, element }... ] // with a separator
|
list ::= element [ {, element }... ] // with a separator
|
||||||
|
@@ -8320,6 +8320,7 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
|
|||||||
my_error(ER_TOO_MANY_TABLES, MYF(0), static_cast<int>(MAX_TABLES));
|
my_error(ER_TOO_MANY_TABLES, MYF(0), static_cast<int>(MAX_TABLES));
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qb_hints && // QB hints initialized
|
if (qb_hints && // QB hints initialized
|
||||||
!table_list->opt_hints_table) // Table hints are not adjusted yet
|
!table_list->opt_hints_table) // Table hints are not adjusted yet
|
||||||
{
|
{
|
||||||
|
@@ -38,7 +38,7 @@
|
|||||||
#include "sql_partition.h"
|
#include "sql_partition.h"
|
||||||
#include "sql_partition_admin.h" // Sql_cmd_alter_table_*_part
|
#include "sql_partition_admin.h" // Sql_cmd_alter_table_*_part
|
||||||
#include "event_parse_data.h"
|
#include "event_parse_data.h"
|
||||||
#include "opt_hints_parser.h"
|
#include "opt_hints.h"
|
||||||
#ifdef WITH_WSREP
|
#ifdef WITH_WSREP
|
||||||
#include "mysql/service_wsrep.h"
|
#include "mysql/service_wsrep.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -5984,6 +5984,84 @@ bool st_select_lex::is_merged_child_of(st_select_lex *ancestor)
|
|||||||
return all_merged;
|
return all_merged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns which subquery execution strategies can be used for this query block.
|
||||||
|
|
||||||
|
@param thd Pointer to THD object for session.
|
||||||
|
Used to access optimizer_switch
|
||||||
|
|
||||||
|
@retval SUBS_MATERIALIZATION Subquery Materialization should be used
|
||||||
|
@retval SUBS_IN_TO_EXISTS In-to-exists execution should be used
|
||||||
|
@retval SUBS_MATERIALIZATION | SUBS_IN_TO_EXISTS A cost-based decision
|
||||||
|
should be made
|
||||||
|
*/
|
||||||
|
uint st_select_lex::subquery_strategies_allowed(THD *thd) const
|
||||||
|
{
|
||||||
|
if (opt_hints_qb && opt_hints_qb->subquery_strategy != SUBS_NOT_TRANSFORMED)
|
||||||
|
return opt_hints_qb->subquery_strategy;
|
||||||
|
|
||||||
|
// No SUBQUERY hint given, base possible strategies on optimizer_switch
|
||||||
|
uint strategy = SUBS_NOT_TRANSFORMED;
|
||||||
|
if (optimizer_flag(thd, OPTIMIZER_SWITCH_MATERIALIZATION))
|
||||||
|
strategy |= SUBS_MATERIALIZATION;
|
||||||
|
if (optimizer_flag(thd, OPTIMIZER_SWITCH_IN_TO_EXISTS))
|
||||||
|
strategy |= SUBS_IN_TO_EXISTS;
|
||||||
|
return strategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns whether semi-join is enabled for this query block
|
||||||
|
|
||||||
|
@see @c Opt_hints_qb::semijoin_enabled for details on how hints
|
||||||
|
affect this decision. If there are no hints for this query block,
|
||||||
|
optimizer_switch setting determines whether semi-join is used.
|
||||||
|
|
||||||
|
@param thd Pointer to THD object for session.
|
||||||
|
Used to access optimizer_switch
|
||||||
|
|
||||||
|
@return true if semijoin is enabled,
|
||||||
|
false otherwise
|
||||||
|
*/
|
||||||
|
bool st_select_lex::semijoin_enabled(THD *thd) const
|
||||||
|
{
|
||||||
|
return opt_hints_qb ?
|
||||||
|
opt_hints_qb->semijoin_enabled(thd) :
|
||||||
|
optimizer_flag(thd, OPTIMIZER_SWITCH_SEMIJOIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Update available semijoin strategies for semijoin nests.
|
||||||
|
|
||||||
|
Available semijoin strategies needs to be updated on every execution since
|
||||||
|
optimizer_switch setting may have changed.
|
||||||
|
|
||||||
|
@param thd Pointer to THD object for session.
|
||||||
|
Used to access optimizer_switch
|
||||||
|
*/
|
||||||
|
void st_select_lex::update_available_semijoin_strategies(THD *thd)
|
||||||
|
{
|
||||||
|
uint sj_strategy_mask= OPTIMIZER_SWITCH_FIRSTMATCH |
|
||||||
|
OPTIMIZER_SWITCH_LOOSE_SCAN | OPTIMIZER_SWITCH_MATERIALIZATION |
|
||||||
|
OPTIMIZER_SWITCH_DUPSWEEDOUT;
|
||||||
|
|
||||||
|
uint opt_switches= thd->variables.optimizer_switch & sj_strategy_mask;
|
||||||
|
|
||||||
|
List_iterator<TABLE_LIST> sj_list_it(sj_nests);
|
||||||
|
TABLE_LIST *sj_nest;
|
||||||
|
while ((sj_nest= sj_list_it++))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
After semi-join transformation, original SELECT_LEX with hints is lost.
|
||||||
|
Fetch hints from first table in semijoin nest.
|
||||||
|
*/
|
||||||
|
List_iterator<TABLE_LIST> table_list(sj_nest->nested_join->join_list);
|
||||||
|
TABLE_LIST *table= table_list++;
|
||||||
|
sj_nest->nested_join->sj_enabled_strategies= table->opt_hints_qb ?
|
||||||
|
table->opt_hints_qb->sj_enabled_strategies(opt_switches) : opt_switches;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This is used by SHOW EXPLAIN|ANALYZE. It assumes query plan has been already
|
This is used by SHOW EXPLAIN|ANALYZE. It assumes query plan has been already
|
||||||
collected into QPF structures and we only need to print it out.
|
collected into QPF structures and we only need to print it out.
|
||||||
|
@@ -1576,6 +1576,9 @@ public:
|
|||||||
{
|
{
|
||||||
parsed_optimizer_hints= hl;
|
parsed_optimizer_hints= hl;
|
||||||
}
|
}
|
||||||
|
uint subquery_strategies_allowed(THD *thd) const;
|
||||||
|
bool semijoin_enabled(THD *thd) const;
|
||||||
|
void update_available_semijoin_strategies(THD *thd);
|
||||||
};
|
};
|
||||||
typedef class st_select_lex SELECT_LEX;
|
typedef class st_select_lex SELECT_LEX;
|
||||||
|
|
||||||
|
@@ -531,7 +531,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Iterator;
|
class Iterator;
|
||||||
class Const_Iterator;
|
|
||||||
using value_type= T;
|
using value_type= T;
|
||||||
using iterator= Iterator;
|
using iterator= Iterator;
|
||||||
iterator begin() const { return iterator(first); }
|
iterator begin() const { return iterator(first); }
|
||||||
@@ -579,49 +578,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
list_node *node{&end_of_list};
|
list_node *node{&end_of_list};
|
||||||
};
|
};
|
||||||
|
|
||||||
class Const_Iterator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using iterator_category= std::forward_iterator_tag;
|
|
||||||
using value_type= const T;
|
|
||||||
using difference_type= std::ptrdiff_t;
|
|
||||||
using pointer= const T *;
|
|
||||||
using reference= const T &;
|
|
||||||
|
|
||||||
Const_Iterator(const list_node *p= &end_of_list) : node{p} {}
|
|
||||||
|
|
||||||
Const_Iterator &operator++()
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(node != &end_of_list);
|
|
||||||
|
|
||||||
node= node->next;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Const_Iterator operator++(int)
|
|
||||||
{
|
|
||||||
Const_Iterator tmp(*this);
|
|
||||||
operator++();
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
const T &operator*() { return *static_cast<const T *>(node->info); }
|
|
||||||
const T *operator->() { return static_cast<const T *>(node->info); }
|
|
||||||
|
|
||||||
bool operator==(const typename List<T>::const_iterator &rhs)
|
|
||||||
{
|
|
||||||
return node == rhs.node;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator!=(const typename List<T>::const_iterator &rhs)
|
|
||||||
{
|
|
||||||
return node != rhs.node;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const list_node* node{&end_of_list};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@@ -140,41 +140,42 @@
|
|||||||
#define OPTIMIZER_SWITCH_DERIVED_WITH_KEYS (1ULL << 7)
|
#define OPTIMIZER_SWITCH_DERIVED_WITH_KEYS (1ULL << 7)
|
||||||
#define OPTIMIZER_SWITCH_FIRSTMATCH (1ULL << 8)
|
#define OPTIMIZER_SWITCH_FIRSTMATCH (1ULL << 8)
|
||||||
#define OPTIMIZER_SWITCH_LOOSE_SCAN (1ULL << 9)
|
#define OPTIMIZER_SWITCH_LOOSE_SCAN (1ULL << 9)
|
||||||
#define OPTIMIZER_SWITCH_MATERIALIZATION (1ULL << 10)
|
#define OPTIMIZER_SWITCH_DUPSWEEDOUT (1ULL << 10)
|
||||||
#define OPTIMIZER_SWITCH_IN_TO_EXISTS (1ULL << 11)
|
#define OPTIMIZER_SWITCH_MATERIALIZATION (1ULL << 11)
|
||||||
#define OPTIMIZER_SWITCH_SEMIJOIN (1ULL << 12)
|
#define OPTIMIZER_SWITCH_IN_TO_EXISTS (1ULL << 12)
|
||||||
#define OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE (1ULL << 13)
|
#define OPTIMIZER_SWITCH_SEMIJOIN (1ULL << 13)
|
||||||
#define OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN (1ULL << 14)
|
#define OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE (1ULL << 14)
|
||||||
#define OPTIMIZER_SWITCH_SUBQUERY_CACHE (1ULL << 15)
|
#define OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN (1ULL << 15)
|
||||||
|
#define OPTIMIZER_SWITCH_SUBQUERY_CACHE (1ULL << 16)
|
||||||
/** If this is off, MRR is never used. */
|
/** If this is off, MRR is never used. */
|
||||||
#define OPTIMIZER_SWITCH_MRR (1ULL << 16)
|
#define OPTIMIZER_SWITCH_MRR (1ULL << 17)
|
||||||
/**
|
/**
|
||||||
If OPTIMIZER_SWITCH_MRR is on and this is on, MRR is used depending on a
|
If OPTIMIZER_SWITCH_MRR is on and this is on, MRR is used depending on a
|
||||||
cost-based choice ("automatic"). If OPTIMIZER_SWITCH_MRR is on and this is
|
cost-based choice ("automatic"). If OPTIMIZER_SWITCH_MRR is on and this is
|
||||||
off, MRR is "forced" (i.e. used as long as the storage engine is capable of
|
off, MRR is "forced" (i.e. used as long as the storage engine is capable of
|
||||||
doing it).
|
doing it).
|
||||||
*/
|
*/
|
||||||
#define OPTIMIZER_SWITCH_MRR_COST_BASED (1ULL << 17)
|
#define OPTIMIZER_SWITCH_MRR_COST_BASED (1ULL << 18)
|
||||||
#define OPTIMIZER_SWITCH_MRR_SORT_KEYS (1ULL << 18)
|
#define OPTIMIZER_SWITCH_MRR_SORT_KEYS (1ULL << 19)
|
||||||
#define OPTIMIZER_SWITCH_OUTER_JOIN_WITH_CACHE (1ULL << 19)
|
#define OPTIMIZER_SWITCH_OUTER_JOIN_WITH_CACHE (1ULL << 20)
|
||||||
#define OPTIMIZER_SWITCH_SEMIJOIN_WITH_CACHE (1ULL << 20)
|
#define OPTIMIZER_SWITCH_SEMIJOIN_WITH_CACHE (1ULL << 21)
|
||||||
#define OPTIMIZER_SWITCH_JOIN_CACHE_INCREMENTAL (1ULL << 21)
|
#define OPTIMIZER_SWITCH_JOIN_CACHE_INCREMENTAL (1ULL << 22)
|
||||||
#define OPTIMIZER_SWITCH_JOIN_CACHE_HASHED (1ULL << 22)
|
#define OPTIMIZER_SWITCH_JOIN_CACHE_HASHED (1ULL << 23)
|
||||||
#define OPTIMIZER_SWITCH_JOIN_CACHE_BKA (1ULL << 23)
|
#define OPTIMIZER_SWITCH_JOIN_CACHE_BKA (1ULL << 24)
|
||||||
#define OPTIMIZER_SWITCH_OPTIMIZE_JOIN_BUFFER_SIZE (1ULL << 24)
|
#define OPTIMIZER_SWITCH_OPTIMIZE_JOIN_BUFFER_SIZE (1ULL << 25)
|
||||||
#define OPTIMIZER_SWITCH_TABLE_ELIMINATION (1ULL << 25)
|
#define OPTIMIZER_SWITCH_TABLE_ELIMINATION (1ULL << 26)
|
||||||
#define OPTIMIZER_SWITCH_EXTENDED_KEYS (1ULL << 26)
|
#define OPTIMIZER_SWITCH_EXTENDED_KEYS (1ULL << 27)
|
||||||
#define OPTIMIZER_SWITCH_EXISTS_TO_IN (1ULL << 27)
|
#define OPTIMIZER_SWITCH_EXISTS_TO_IN (1ULL << 28)
|
||||||
#define OPTIMIZER_SWITCH_ORDERBY_EQ_PROP (1ULL << 28)
|
#define OPTIMIZER_SWITCH_ORDERBY_EQ_PROP (1ULL << 29)
|
||||||
#define OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED (1ULL << 29)
|
#define OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED (1ULL << 30)
|
||||||
#define OPTIMIZER_SWITCH_SPLIT_MATERIALIZED (1ULL << 30)
|
#define OPTIMIZER_SWITCH_SPLIT_MATERIALIZED (1ULL << 31)
|
||||||
#define OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_SUBQUERY (1ULL << 31)
|
#define OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_SUBQUERY (1ULL << 32)
|
||||||
#define OPTIMIZER_SWITCH_USE_ROWID_FILTER (1ULL << 32)
|
#define OPTIMIZER_SWITCH_USE_ROWID_FILTER (1ULL << 33)
|
||||||
#define OPTIMIZER_SWITCH_COND_PUSHDOWN_FROM_HAVING (1ULL << 33)
|
#define OPTIMIZER_SWITCH_COND_PUSHDOWN_FROM_HAVING (1ULL << 34)
|
||||||
#define OPTIMIZER_SWITCH_NOT_NULL_RANGE_SCAN (1ULL << 34)
|
#define OPTIMIZER_SWITCH_NOT_NULL_RANGE_SCAN (1ULL << 35)
|
||||||
#define OPTIMIZER_SWITCH_HASH_JOIN_CARDINALITY (1ULL << 35)
|
#define OPTIMIZER_SWITCH_HASH_JOIN_CARDINALITY (1ULL << 36)
|
||||||
#define OPTIMIZER_SWITCH_CSET_NARROWING (1ULL << 36)
|
#define OPTIMIZER_SWITCH_CSET_NARROWING (1ULL << 37)
|
||||||
#define OPTIMIZER_SWITCH_SARGABLE_CASEFOLD (1ULL << 37)
|
#define OPTIMIZER_SWITCH_SARGABLE_CASEFOLD (1ULL << 38)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -208,6 +209,7 @@
|
|||||||
OPTIMIZER_SWITCH_SEMIJOIN | \
|
OPTIMIZER_SWITCH_SEMIJOIN | \
|
||||||
OPTIMIZER_SWITCH_FIRSTMATCH | \
|
OPTIMIZER_SWITCH_FIRSTMATCH | \
|
||||||
OPTIMIZER_SWITCH_LOOSE_SCAN | \
|
OPTIMIZER_SWITCH_LOOSE_SCAN | \
|
||||||
|
OPTIMIZER_SWITCH_DUPSWEEDOUT | \
|
||||||
OPTIMIZER_SWITCH_EXISTS_TO_IN | \
|
OPTIMIZER_SWITCH_EXISTS_TO_IN | \
|
||||||
OPTIMIZER_SWITCH_ORDERBY_EQ_PROP | \
|
OPTIMIZER_SWITCH_ORDERBY_EQ_PROP | \
|
||||||
OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED | \
|
OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED | \
|
||||||
|
@@ -5601,6 +5601,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
|
|||||||
DBUG_ENTER("make_join_statistics");
|
DBUG_ENTER("make_join_statistics");
|
||||||
|
|
||||||
table_count=join->table_count;
|
table_count=join->table_count;
|
||||||
|
const uint sj_nests= join->select_lex->sj_nests.elements; // Changed by pull-out
|
||||||
|
|
||||||
/*
|
/*
|
||||||
best_extension_by_limited_search need sort space for 2POSITIION
|
best_extension_by_limited_search need sort space for 2POSITIION
|
||||||
@@ -6316,6 +6317,9 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
|
|||||||
join->const_tables=const_count;
|
join->const_tables=const_count;
|
||||||
join->found_const_table_map=found_const_table_map;
|
join->found_const_table_map=found_const_table_map;
|
||||||
|
|
||||||
|
if (sj_nests)
|
||||||
|
join->select_lex->update_available_semijoin_strategies(thd);
|
||||||
|
|
||||||
if (join->const_tables != join->table_count)
|
if (join->const_tables != join->table_count)
|
||||||
optimize_keyuse(join, keyuse_array);
|
optimize_keyuse(join, keyuse_array);
|
||||||
|
|
||||||
|
@@ -805,6 +805,12 @@ public:
|
|||||||
|
|
||||||
virtual void mark_used() = 0;
|
virtual void mark_used() = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Returns TRUE if the strategy is disabled by either optimizer switch
|
||||||
|
setting or an optimizer hint
|
||||||
|
*/
|
||||||
|
virtual bool is_disabled() const { return false; }
|
||||||
|
|
||||||
virtual ~Semi_join_strategy_picker() = default;
|
virtual ~Semi_join_strategy_picker() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -825,12 +831,15 @@ class Duplicate_weedout_picker : public Semi_join_strategy_picker
|
|||||||
table_map dupsweedout_tables;
|
table_map dupsweedout_tables;
|
||||||
|
|
||||||
bool is_used;
|
bool is_used;
|
||||||
|
|
||||||
|
bool disabled; // See comment for Semi_join_strategy_picker::is_disabled()
|
||||||
public:
|
public:
|
||||||
void set_empty() override
|
void set_empty() override
|
||||||
{
|
{
|
||||||
dupsweedout_tables= 0;
|
dupsweedout_tables= 0;
|
||||||
first_dupsweedout_table= MAX_TABLES;
|
first_dupsweedout_table= MAX_TABLES;
|
||||||
is_used= FALSE;
|
is_used= FALSE;
|
||||||
|
disabled= FALSE;
|
||||||
}
|
}
|
||||||
void set_from_prev(POSITION *prev) override;
|
void set_from_prev(POSITION *prev) override;
|
||||||
|
|
||||||
@@ -845,6 +854,9 @@ public:
|
|||||||
POSITION *loose_scan_pos) override;
|
POSITION *loose_scan_pos) override;
|
||||||
|
|
||||||
void mark_used() override { is_used= TRUE; }
|
void mark_used() override { is_used= TRUE; }
|
||||||
|
|
||||||
|
bool is_disabled() const override { return disabled; }
|
||||||
|
|
||||||
friend void fix_semijoin_strategies_for_picked_join_order(JOIN *join);
|
friend void fix_semijoin_strategies_for_picked_join_order(JOIN *join);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -3043,7 +3043,8 @@ export const char *optimizer_switch_names[]=
|
|||||||
"index_merge_intersection","index_merge_sort_intersection",
|
"index_merge_intersection","index_merge_sort_intersection",
|
||||||
"index_condition_pushdown",
|
"index_condition_pushdown",
|
||||||
"derived_merge", "derived_with_keys",
|
"derived_merge", "derived_with_keys",
|
||||||
"firstmatch","loosescan","materialization","in_to_exists","semijoin",
|
"firstmatch","loosescan","duplicateweedout","materialization",
|
||||||
|
"in_to_exists","semijoin",
|
||||||
"partial_match_rowid_merge",
|
"partial_match_rowid_merge",
|
||||||
"partial_match_table_scan",
|
"partial_match_table_scan",
|
||||||
"subquery_cache",
|
"subquery_cache",
|
||||||
|
@@ -3447,6 +3447,10 @@ typedef struct st_nested_join
|
|||||||
table_map sj_corr_tables;
|
table_map sj_corr_tables;
|
||||||
table_map direct_children_map;
|
table_map direct_children_map;
|
||||||
List<Item_ptr> sj_outer_expr_list;
|
List<Item_ptr> sj_outer_expr_list;
|
||||||
|
|
||||||
|
/// Bitmap of which strategies are enabled for this semi-join nest
|
||||||
|
uint sj_enabled_strategies;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
True if this join nest node is completely covered by the query execution
|
True if this join nest node is completely covered by the query execution
|
||||||
plan. This means two things.
|
plan. This means two things.
|
||||||
|
Reference in New Issue
Block a user