1
0
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:
Oleg Smirnov
2024-09-11 19:53:57 +07:00
parent e3bf4c826c
commit 2c8f6058c1
28 changed files with 3712 additions and 164 deletions

View File

@@ -8,7 +8,7 @@
set @save_optimizer_switch=@@optimizer_switch;
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_search_depth=62;

View File

@@ -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_intersection, index_condition_pushdown,
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,
subquery_cache, mrr, mrr_cost_based, mrr_sort_keys,
outer_join_with_cache, semijoin_with_cache,
@@ -1889,7 +1889,7 @@ optimizer-rowid-copy-cost 0.002653
optimizer-scan-setup-cost 10
optimizer-search-depth 62
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-max-mem-size 1048576
optimizer-use-condition-selectivity 4

View File

@@ -33,7 +33,7 @@ set @save_optimizer_switch=@@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';
-- 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 @@session.session_track_system_variables= @save_session_track_system_variables;

View File

@@ -1,4 +1,6 @@
--source include/not_embedded.inc
--source include/have_sequence.inc
--echo #
--echo # MAX_EXECUTION_TIME hint testing
--echo #

View File

@@ -56,6 +56,7 @@ ANALYZE TABLE t3;
set optimizer_switch=default;
--disable_ps2_protocol
--disable_cursor_protocol
--echo # Check statistics with no hint
FLUSH STATUS;
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;
SHOW STATUS LIKE 'handler_read%';
--enable_ps2_protocol
--enable_cursor_protocol
EXPLAIN EXTENDED SELECT f1 FROM t3 WHERE f1 > 30 AND f1 < 33;
--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);
--disable_ps2_protocol
--disable_cursor_protocol
--echo # Check statistics without hint
FLUSH STATUS;
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);
SHOW STATUS LIKE 'handler_read%';
--enable_ps2_protocol
--enable_cursor_protocol
EXPLAIN EXTENDED SELECT /*+ BKA(t13) */ * FROM t12, t13
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
--disable_ps2_protocol
--disable_cursor_protocol
--echo # Check that PS and conventional statements give the same result.
FLUSH STATUS;
SELECT /*+ BKA(t13) */ * FROM t12, t13 WHERE t12.a=t13.a AND (t13.b+1 <= t13.b+1);
SHOW STATUS LIKE 'handler_read%';
--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)";
FLUSH STATUS;
@@ -388,6 +394,7 @@ CREATE TABLE t3 (a INT, b INT);
INSERT INTO t3 VALUES (1,1),(2,2);
--disable_ps2_protocol
--disable_cursor_protocol
--echo # Check statistics without hint
FLUSH STATUS;
SELECT t1.* FROM t1,t2,t3;
@@ -398,6 +405,7 @@ FLUSH STATUS;
SELECT /*+ NO_BNL() */t1.* FROM t1,t2,t3;
SHOW STATUS LIKE 'handler_read%';
--enable_ps2_protocol
--enable_cursor_protocol
EXPLAIN EXTENDED SELECT 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';
--disable_ps2_protocol
--disable_cursor_protocol
--echo # Check statistics without hint
FLUSH STATUS;
SELECT * FROM t1 WHERE f2 <= 3 AND 3 <= f3;
@@ -725,6 +734,7 @@ SHOW STATUS LIKE 'handler_read%';
DROP PROCEDURE p;
--enable_ps2_protocol
--enable_cursor_protocol
EXPLAIN EXTENDED SELECT * FROM t1 WHERE f2 <= 3 AND 3 <= f3;
--echo # Turn off MRR. MRR should not be used.

File diff suppressed because it is too large Load Diff

View 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;

View File

@@ -1,58 +1,58 @@
set @@global.optimizer_switch=@@optimizer_switch;
select @@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;
@@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';
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';
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';
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';
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
set global optimizer_switch=2053;
set session optimizer_switch=1034;
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=4101;
set session optimizer_switch=2058;
select @@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;
@@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 session optimizer_switch="index_merge=off";
select @@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;
@@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';
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';
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';
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';
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";
select @@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');
select @@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;
ERROR 42000: Incorrect argument type to variable 'optimizer_switch'
set global optimizer_switch=1e1;

View File

@@ -2649,7 +2649,7 @@ VARIABLE_COMMENT Fine-tune the optimizer behavior
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE 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
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME OPTIMIZER_TRACE

View File

@@ -2869,7 +2869,7 @@ VARIABLE_COMMENT Fine-tune the optimizer behavior
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE 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
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME OPTIMIZER_TRACE

View File

@@ -19,8 +19,8 @@ select * from information_schema.session_variables where variable_name='optimize
#
# show that it's writable
#
set global optimizer_switch=2053;
set session optimizer_switch=1034;
set global optimizer_switch=4101;
set session optimizer_switch=2058;
select @@global.optimizer_switch;
select @@session.optimizer_switch;
set global optimizer_switch="index_merge_sort_union=on";

View File

@@ -6,6 +6,7 @@ condition_pushdown_from_having on
cset_narrowing on
derived_merge on
derived_with_keys on
duplicateweedout on
exists_to_in on
extended_keys on
firstmatch on

View File

@@ -40,6 +40,8 @@ struct st_opt_hint_info opt_hint_info[]=
{{STRING_WITH_LEN("NO_RANGE_OPTIMIZATION")}, true, false},
{{STRING_WITH_LEN("QB_NAME")}, false, false},
{{STRING_WITH_LEN("MAX_EXECUTION_TIME")}, false, true},
{{STRING_WITH_LEN("SEMIJOIN")}, false, true},
{{STRING_WITH_LEN("SUBQUERY")}, false, true},
{null_clex_str, 0, 0}
};
@@ -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 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)
{
@@ -122,7 +125,7 @@ void print_warn(THD *thd, uint err_code, opt_hints_enum hint_type,
/* Append additional hint arguments if they exist */
if (hint)
{
if (qb_name_arg || table_name_arg || key_name_arg)
if (got_qb_name || table_name_arg || key_name_arg)
str.append(' ');
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)
{
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;
}
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
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;
}
/*
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;
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))
{
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;
}
@@ -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);
Opt_hints_table *tab= get_table_hints(pc, table_name_sys, qb);
if (!tab)
return true;
return false;
if (tab->set_switch(hint_state, hint_type, true))
{
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
&qb_name_sys, &table_name_sys, 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))
{
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;
}
@@ -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);
Opt_hints_table *tab= get_table_hints(pc, table_name_sys, qb);
if (!tab)
return true;
return false;
if (tab->set_switch(hint_state, hint_type, true))
{
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
&null_ident_sys, &table_name_sys,
NULL, (Parser::Hint*) NULL);
&null_ident_sys, &table_name_sys, nullptr,
(Parser::Hint*) nullptr);
}
}
@@ -610,18 +662,27 @@ bool Optimizer_hint_parser::Table_level_hint::resolve(Parse_context *pc) const
to_ident_sys(pc->thd);
Opt_hints_table *tab= get_table_hints(pc, table_name_sys, qb);
if (!tab)
return true;
return false;
if (tab->set_switch(hint_state, hint_type, true))
{
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
&qb_name_sys, &table_name_sys, NULL, (Parser::Hint*) NULL);
&qb_name_sys, &table_name_sys, nullptr,
(Parser::Hint*) nullptr);
}
}
}
return false;
}
/*
Resolve a parsed index level hint, i.e. set up proper Opt_hint_* structures
which will be used later during query preparation and optimization.
Return value:
- false: no critical errors, warnings on duplicated hints,
unresolved query block names, etc. are allowed
- true: critical errors detected, break further hints processing
*/
bool Parser::Index_level_hint::resolve(Parse_context *pc) const
{
const Index_level_hint_type &index_level_hint_type= *this;
@@ -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);
if (!tab)
return true;
return false;
if (is_empty()) // Table level hint
{
if (tab->set_switch(hint_state, hint_type, false))
{
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
&qb_name_sys, &table_name_sys, NULL, (Parser::Hint*) NULL);
&qb_name_sys, &table_name_sys, nullptr,
(Parser::Hint*) nullptr);
}
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,
&qb_name_sys, &table_name_sys, &index_name_sys,
(Parser::Hint*) NULL);
(Parser::Hint*) nullptr);
}
}
return false;
}
/*
Resolve a parsed query block name hint, i.e. set up proper Opt_hint_*
structures which will be used later during query preparation and optimization.
Return value:
- false: no critical errors, warnings on duplicated hints,
unresolved query block names, etc. are allowed
- true: critical errors detected, break further hints processing
*/
bool Parser::Qb_name_hint::resolve(Parse_context *pc) const
{
Opt_hints_qb *qb= pc->select->opt_hints_qb;
@@ -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
{
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;
}
@@ -717,6 +786,270 @@ bool Parser::Qb_name_hint::resolve(Parse_context *pc) const
return false;
}
void Parser::Semijoin_hint::fill_strategies_map(Opt_hints_qb *qb) const
{
// Loop for hints like SEMIJOIN(firstmatch, dupsweedout)
const Hint_param_opt_sj_strategy_list &hint_param_strategy_list= *this;
for (const Semijoin_strategy &strat : hint_param_strategy_list)
add_strategy_to_map(strat.id(), qb);
// Loop for hints like SEMIJOIN(@qb1 firstmatch, dupsweedout)
const Opt_sj_strategy_list &opt_sj_strategy_list= *this;
for (const Semijoin_strategy &strat : opt_sj_strategy_list)
add_strategy_to_map(strat.id(), qb);
}
void Parser::Semijoin_hint::add_strategy_to_map(TokenID token_id,
Opt_hints_qb *qb) const
{
switch(token_id)
{
case TokenID::keyword_DUPSWEEDOUT:
qb->semijoin_strategies_map |= OPTIMIZER_SWITCH_DUPSWEEDOUT;
break;
case TokenID::keyword_FIRSTMATCH:
qb->semijoin_strategies_map |= OPTIMIZER_SWITCH_FIRSTMATCH;
break;
case TokenID::keyword_LOOSESCAN:
qb->semijoin_strategies_map |= OPTIMIZER_SWITCH_LOOSE_SCAN;
break;
case TokenID::keyword_MATERIALIZATION:
qb->semijoin_strategies_map |= OPTIMIZER_SWITCH_MATERIALIZATION;
break;
default:
DBUG_ASSERT(0);
}
}
/*
Resolve a parsed semijoin hint, i.e. set up proper Opt_hint_* structures
which will be used later during query preparation and optimization.
Return value:
- false: no critical errors, warnings on duplicated hints,
unresolved query block names, etc. are allowed
- true: critical errors detected, break further hints processing
*/
bool Parser::Semijoin_hint::resolve(Parse_context *pc) const
{
const Semijoin_hint_type &semijoin_hint_type= *this;
bool hint_state; // true - SEMIJOIN(), false - NO_SEMIJOIN()
if (semijoin_hint_type.id() == TokenID::keyword_SEMIJOIN)
hint_state= true;
else
hint_state= false;
Opt_hints_qb *qb;
if (const At_query_block_name_opt_strategy_list &
at_query_block_name_opt_strategy_list __attribute__((unused)) = *this)
{
/*
This is @ query_block_name opt_strategy_list,
e.g. SEMIJOIN(@qb1) or SEMIJOIN(@qb1 firstmatch, loosescan)
*/
const Lex_ident_sys qb_name= Query_block_name::to_ident_sys(pc->thd);
qb= resolve_for_qb_name(pc, hint_state, &qb_name);
}
else
{
// This is opt_strategy_list, e.g. SEMIJOIN(loosescan, dupsweedout)
Lex_ident_sys empty_qb_name= Lex_ident_sys();
qb= resolve_for_qb_name(pc, hint_state, &empty_qb_name);
}
if (qb)
qb->semijoin_hint= this;
return false;
}
/*
Helper function to be called by Semijoin_hint::resolve().
Return value:
- pointer to Opt_hints_qb if the hint was resolved successfully
- NULL if the hint was ignored
*/
Opt_hints_qb* Parser::Semijoin_hint::resolve_for_qb_name(Parse_context *pc,
bool hint_state, const Lex_ident_sys *qb_name) const
{
Opt_hints_qb *qb= find_qb_hints(pc, *qb_name, SEMIJOIN_HINT_ENUM, hint_state);
if (!qb)
return nullptr;
if (qb->subquery_hint)
{
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, SEMIJOIN_HINT_ENUM,
hint_state, qb_name, nullptr, nullptr, this);
return nullptr;
}
if (qb->set_switch(hint_state, SEMIJOIN_HINT_ENUM, false))
{
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, SEMIJOIN_HINT_ENUM,
hint_state, qb_name, nullptr, nullptr, this);
return nullptr;
}
fill_strategies_map(qb);
return qb;
}
void Parser::Semijoin_hint::append_args(THD *thd, String *str) const
{
// Loop for hints without query block name, e.g. SEMIJOIN(firstmatch, dupsweedout)
const Hint_param_opt_sj_strategy_list &hint_param_strategy_list= *this;
uint32 len_before= str->length();
for (const Semijoin_strategy &strat : hint_param_strategy_list)
{
if (str->length() > len_before)
str->append(STRING_WITH_LEN(", "));
append_strategy_name(strat.id(), str);
}
// Loop for hints with query block name, e.g. SEMIJOIN(@qb1 firstmatch, dupsweedout)
const Opt_sj_strategy_list &opt_sj_strategy_list= *this;
for (const Semijoin_strategy &strat : opt_sj_strategy_list)
{
if (str->length() > len_before)
str->append(STRING_WITH_LEN(", "));
append_strategy_name(strat.id(), str);
}
}
void Parser::Semijoin_hint::
append_strategy_name(TokenID token_id, String *str) const
{
switch(token_id)
{
case TokenID::keyword_DUPSWEEDOUT:
str->append(STRING_WITH_LEN("DUPSWEEDOUT"));
break;
case TokenID::keyword_FIRSTMATCH:
str->append(STRING_WITH_LEN("FIRSTMATCH"));
break;
case TokenID::keyword_LOOSESCAN:
str->append(STRING_WITH_LEN("LOOSESCAN"));
break;
case TokenID::keyword_MATERIALIZATION:
str->append(STRING_WITH_LEN("MATERIALIZATION"));
break;
default:
DBUG_ASSERT(0);
}
}
/*
Resolve a parsed subquery hint, i.e. set up proper Opt_hint_* structures
which will be used later during query preparation and optimization.
Return value:
- false: no critical errors, warnings on duplicated hints,
unresolved query block names, etc. are allowed
- true: critical errors detected, break further hints processing
*/
bool Parser::Subquery_hint::resolve(Parse_context *pc) const
{
Opt_hints_qb *qb;
if (const At_query_block_name_subquery_strategy &
at_query_block_name_subquery_strategy= *this)
{
/*
This is @ query_block_name subquery_strategy,
e.g. SUBQUERY(@qb1 INTOEXISTS)
*/
const Lex_ident_sys qb_name= Query_block_name::to_ident_sys(pc->thd);
const Subquery_strategy &strat= at_query_block_name_subquery_strategy;
qb= resolve_for_qb_name(pc, strat.id(), &qb_name);
}
else
{
// This is subquery_strategy, e.g. SUBQUERY(MATERIALIZATION)
Lex_ident_sys empty_qb_name= Lex_ident_sys();
const Hint_param_subquery_strategy &strat= *this;
qb= resolve_for_qb_name(pc, strat.id(), &empty_qb_name);
}
if (qb)
qb->subquery_hint= this;
return false;
}
/*
Helper function to be called by Subquery_hint::resolve().
Return value:
- pointer to Opt_hints_qb if the hint was resolved successfully
- NULL if the hint was ignored
*/
Opt_hints_qb* Parser::Subquery_hint::resolve_for_qb_name(Parse_context *pc,
TokenID token_id, const Lex_ident_sys *qb_name) const
{
Opt_hints_qb *qb= find_qb_hints(pc, *qb_name, SUBQUERY_HINT_ENUM, true);
if (!qb)
return nullptr;
if (qb->semijoin_hint)
{
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, SUBQUERY_HINT_ENUM,
true, qb_name, nullptr, nullptr, this);
return nullptr;
}
if (qb->set_switch(true, SUBQUERY_HINT_ENUM, false))
{
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, SUBQUERY_HINT_ENUM,
true, qb_name, nullptr, nullptr, this);
return nullptr;
}
set_subquery_strategy(token_id, qb);
return qb;
}
void Parser::Subquery_hint::set_subquery_strategy(TokenID token_id,
Opt_hints_qb *qb) const
{
switch(token_id)
{
case TokenID::keyword_INTOEXISTS:
qb->subquery_strategy= SUBS_IN_TO_EXISTS;
break;
case TokenID::keyword_MATERIALIZATION:
qb->subquery_strategy= SUBS_MATERIALIZATION;
break;
default:
DBUG_ASSERT(0);
}
}
void Parser::Subquery_hint::append_args(THD *thd, String *str) const
{
TokenID token_id;
if (const At_query_block_name_subquery_strategy &
at_query_block_name_subquery_strategy= *this)
{
const Subquery_strategy &strat= at_query_block_name_subquery_strategy;
token_id= strat.id();
}
else
{
const Hint_param_subquery_strategy& hint_param_strat= *this;
token_id= hint_param_strat.id();
}
switch(token_id)
{
case TokenID::keyword_INTOEXISTS:
str->append(STRING_WITH_LEN("INTOEXISTS"));
break;
case TokenID::keyword_MATERIALIZATION:
str->append(STRING_WITH_LEN("MATERIALIZATION"));
break;
default:
DBUG_ASSERT(0);
}
}
/*
This is the first step of MAX_EXECUTION_TIME() hint resolution. It is invoked
during the parsing phase, but at this stage some essential information is
@@ -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;
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)
{
if (!max_exec_time_hint || thd->lex->is_ps_or_view_context_analysis())
if (thd->lex->is_ps_or_view_context_analysis())
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
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)
{
@@ -838,6 +1178,19 @@ bool Optimizer_hint_parser::Hint_list::resolve(Parse_context *pc) const
if (max_hint.resolve(pc))
return true;
}
else if (const Semijoin_hint &sj_hint= hint)
{
if (sj_hint.resolve(pc))
return true;
}
else if (const Subquery_hint &subq_hint= hint)
{
if (subq_hint.resolve(pc))
return true;
}
else {
DBUG_ASSERT(0);
}
}
return false;
}

View File

@@ -38,8 +38,9 @@
== Hint "adjustment" ==
During Name Resolution, setup_tables() calls adjust_table_hints() for each
table and sets TABLE_LIST::opt_hints_table to point to its Opt_hints_table.
During Name Resolution, setup_tables() calls adjust_hints_for_table() for
each table and sets TABLE_LIST::opt_hints_table to point to its
Opt_hints_table.
== Hint hierarchy ==
@@ -76,6 +77,7 @@
#include "mysqld_error.h"
#include "opt_hints_parser.h"
struct LEX;
struct TABLE;
@@ -93,7 +95,9 @@ enum opt_hints_enum
NO_RANGE_HINT_ENUM,
QB_NAME_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_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 */
Mem_root_array<Opt_hints*, true> child_array;
/* true if hint is connected to the real object */
bool resolved;
/* Number of resolved children */
@@ -256,6 +262,7 @@ public:
*/
bool get_switch(opt_hints_enum type_arg) const;
/* Collation for comparing the name of this hint */
virtual CHARSET_INFO *charset_info() const
{
return Lex_ident_column::charset_info();
@@ -339,7 +346,11 @@ protected:
Override this function in descendants so that print_warn_unresolved()
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
public:
Opt_hints_qb(Opt_hints *opt_hints_arg,
MEM_ROOT *mem_root_arg,
uint select_number_arg);
@@ -428,6 +438,23 @@ public:
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
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,
NULL otherwise.
*/
Opt_hints_table *adjust_table_hints(TABLE *table,
Opt_hints_table *adjust_hints_for_table(TABLE *table,
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();
}
/**
Append table name.
@@ -477,6 +541,7 @@ public:
append_identifier(thd, str, &name);
get_parent()->append_name(thd, str);
}
/**
Function sets correlation between key hint objects and
appropriate KEY structures.

View File

@@ -57,6 +57,37 @@ Optimizer_hint_tokenizer::find_keyword(const LEX_CSTRING &str)
return TokenID::keyword_QB_NAME;
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:
if ("MAX_EXECUTION_TIME"_Lex_ident_column.streq(str))
return TokenID::keyword_MAX_EXECUTION_TIME;
@@ -220,3 +251,16 @@ Optimizer_hint_parser::
*pe= std::move(elem);
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);
}

View File

@@ -26,6 +26,7 @@
#include "simple_parser.h"
class st_select_lex;
class Opt_hints_qb;
/**
Environment data for the name resolution phase
@@ -74,6 +75,14 @@ public:
keyword_MRR,
keyword_QB_NAME,
keyword_MAX_EXECUTION_TIME,
keyword_SEMIJOIN,
keyword_NO_SEMIJOIN,
keyword_SUBQUERY,
keyword_MATERIALIZATION,
keyword_FIRSTMATCH,
keyword_LOOSESCAN,
keyword_DUPSWEEDOUT,
keyword_INTOEXISTS,
// Other token types
tIDENT,
@@ -250,6 +259,12 @@ private:
using TOKEN::TOKEN;
};
class Keyword_SUBQUERY: public TOKEN<Parser, TokenID::keyword_SUBQUERY>
{
public:
using TOKEN::TOKEN;
};
class Identifier: public TOKEN<Parser, TokenID::tIDENT>
{
public:
@@ -344,10 +359,8 @@ private:
using TokenChoice::TokenChoice;
};
// Identifiers of various kinds
// query_block_name ::= identifier
class Query_block_name: public Identifier
{
@@ -599,25 +612,230 @@ public:
bool resolve(Parse_context *pc) 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
| table_level_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,
Table_level_hint,
Qb_name_hint,
Max_execution_time_hint>
Max_execution_time_hint,
Semijoin_hint,
Subquery_hint>
{
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:
// hint_list ::= hint [ hint... ]
@@ -630,6 +848,7 @@ private:
size_t count() const { return elements; }
};
class Hint_list: public LIST<Parser, Hint_list_container,
Hint, TokenID::tNULL/*not separated list*/, 1>
{
@@ -649,12 +868,11 @@ public:
public:
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.
(forward declarations of qualified nested classes are not possible in C++)
*/
@@ -664,5 +882,4 @@ public:
using Hints::Hints;
};
#endif // OPT_HINTS_PARSER

View File

@@ -466,6 +466,7 @@ enum_nested_loop_state
end_sj_materialize(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
/*
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.
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).
TODO: this is a limitation that can be fixed
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.
*/
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
parent_unit->first_select()->leaf_tables.elements && // 2
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(),
look for calls to block_conversion_to_sj().
*/
if (optimizer_flag(thd, OPTIMIZER_SWITCH_SEMIJOIN) &&
if (select_lex->semijoin_enabled(thd) &&
in_subs && // 1
!select_lex->is_part_of_union() && // 2
!select_lex->group_list.elements && !join->order && // 3
@@ -816,7 +818,7 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
with jtbm strategy
*/
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;
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
allowed it via an optimizer switch, or if materialization is not
allowed it via an optimizer switch/hint, or if materialization is not
possible.
*/
if (optimizer_flag(thd, OPTIMIZER_SWITCH_IN_TO_EXISTS) ||
!in_subs->has_strategy())
uint strategies_allowed= select_lex->subquery_strategies_allowed(thd);
if (strategies_allowed & SUBS_IN_TO_EXISTS || !in_subs->has_strategy())
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;
/*
The statement may have been executed with 'semijoin=on' earlier.
We need to verify that 'semijoin=on' still holds.
The statement may have been executed as a semijoin earlier.
We need to verify that semijoin materialization is still allowed.
*/
if (optimizer_flag(join->thd, OPTIMIZER_SWITCH_SEMIJOIN) &&
optimizer_flag(join->thd, OPTIMIZER_SWITCH_MATERIALIZATION))
if (sj_nest->nested_join->sj_enabled_strategies &
OPTIMIZER_SWITCH_MATERIALIZATION)
{
if ((sj_nest->sj_inner_tables & ~join->const_table_map) && /* not everything was pulled out */
!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
*current_read_time is updated and the cost for the next
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 &&
!(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);
/*
@@ -3481,7 +3493,8 @@ bool Firstmatch_picker::check_qep(JOIN *join,
POSITION *loose_scan_pos)
{
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)
{
const table_map outer_corr_tables=
@@ -3725,10 +3738,22 @@ bool Duplicate_weedout_picker::check_qep(JOIN *join,
POSITION *p= join->positions + j;
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);
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
{
@@ -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_map suffix= remaining_tables & ~tab->table->map;
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

View File

@@ -117,6 +117,7 @@ public:
bound
5. But some of the IN-equalities aren't (so this can't be handled by
FirstMatch strategy)
6. LooseScan strategy is enabled for this SJ nest
*/
best_loose_scan_cost= DBL_MAX;
if (!join->emb_sjm_nest && s->emb_sj_nest && // (1)
@@ -127,7 +128,8 @@ public:
!(remaining_tables &
s->emb_sj_nest->nested_join->sj_corr_tables) && // (4)
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 */
bound_sj_equalities= get_bound_sj_equalities(s->emb_sj_nest,

View File

@@ -478,10 +478,9 @@ protected:
/*
A rule consisting of a choice of four rules:
rule ::= rule1 | rule2 | rule3 | rule4
For the case when the three branches have incompatible storage
A rule consisting of a choice of four rules:
rule ::= rule1 | rule2 | rule3 | rule4
For the case when the four branches have incompatible storage
*/
template<class PARSER, class A, class B, class C, class 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:
list ::= element [ {, element }... ] // with a separator

View File

@@ -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));
DBUG_RETURN(1);
}
if (qb_hints && // QB hints initialized
!table_list->opt_hints_table) // Table hints are not adjusted yet
{

View File

@@ -38,7 +38,7 @@
#include "sql_partition.h"
#include "sql_partition_admin.h" // Sql_cmd_alter_table_*_part
#include "event_parse_data.h"
#include "opt_hints_parser.h"
#include "opt_hints.h"
#ifdef WITH_WSREP
#include "mysql/service_wsrep.h"
#endif
@@ -5984,6 +5984,84 @@ bool st_select_lex::is_merged_child_of(st_select_lex *ancestor)
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
collected into QPF structures and we only need to print it out.

View File

@@ -1576,6 +1576,9 @@ public:
{
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;

View File

@@ -531,7 +531,6 @@ public:
}
class Iterator;
class Const_Iterator;
using value_type= T;
using iterator= Iterator;
iterator begin() const { return iterator(first); }
@@ -579,49 +578,6 @@ public:
private:
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};
};
};

View File

@@ -140,41 +140,42 @@
#define OPTIMIZER_SWITCH_DERIVED_WITH_KEYS (1ULL << 7)
#define OPTIMIZER_SWITCH_FIRSTMATCH (1ULL << 8)
#define OPTIMIZER_SWITCH_LOOSE_SCAN (1ULL << 9)
#define OPTIMIZER_SWITCH_MATERIALIZATION (1ULL << 10)
#define OPTIMIZER_SWITCH_IN_TO_EXISTS (1ULL << 11)
#define OPTIMIZER_SWITCH_SEMIJOIN (1ULL << 12)
#define OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE (1ULL << 13)
#define OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN (1ULL << 14)
#define OPTIMIZER_SWITCH_SUBQUERY_CACHE (1ULL << 15)
#define OPTIMIZER_SWITCH_DUPSWEEDOUT (1ULL << 10)
#define OPTIMIZER_SWITCH_MATERIALIZATION (1ULL << 11)
#define OPTIMIZER_SWITCH_IN_TO_EXISTS (1ULL << 12)
#define OPTIMIZER_SWITCH_SEMIJOIN (1ULL << 13)
#define OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE (1ULL << 14)
#define OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN (1ULL << 15)
#define OPTIMIZER_SWITCH_SUBQUERY_CACHE (1ULL << 16)
/** 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
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
doing it).
*/
#define OPTIMIZER_SWITCH_MRR_COST_BASED (1ULL << 17)
#define OPTIMIZER_SWITCH_MRR_SORT_KEYS (1ULL << 18)
#define OPTIMIZER_SWITCH_OUTER_JOIN_WITH_CACHE (1ULL << 19)
#define OPTIMIZER_SWITCH_SEMIJOIN_WITH_CACHE (1ULL << 20)
#define OPTIMIZER_SWITCH_JOIN_CACHE_INCREMENTAL (1ULL << 21)
#define OPTIMIZER_SWITCH_JOIN_CACHE_HASHED (1ULL << 22)
#define OPTIMIZER_SWITCH_JOIN_CACHE_BKA (1ULL << 23)
#define OPTIMIZER_SWITCH_OPTIMIZE_JOIN_BUFFER_SIZE (1ULL << 24)
#define OPTIMIZER_SWITCH_TABLE_ELIMINATION (1ULL << 25)
#define OPTIMIZER_SWITCH_EXTENDED_KEYS (1ULL << 26)
#define OPTIMIZER_SWITCH_EXISTS_TO_IN (1ULL << 27)
#define OPTIMIZER_SWITCH_ORDERBY_EQ_PROP (1ULL << 28)
#define OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED (1ULL << 29)
#define OPTIMIZER_SWITCH_SPLIT_MATERIALIZED (1ULL << 30)
#define OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_SUBQUERY (1ULL << 31)
#define OPTIMIZER_SWITCH_USE_ROWID_FILTER (1ULL << 32)
#define OPTIMIZER_SWITCH_COND_PUSHDOWN_FROM_HAVING (1ULL << 33)
#define OPTIMIZER_SWITCH_NOT_NULL_RANGE_SCAN (1ULL << 34)
#define OPTIMIZER_SWITCH_HASH_JOIN_CARDINALITY (1ULL << 35)
#define OPTIMIZER_SWITCH_CSET_NARROWING (1ULL << 36)
#define OPTIMIZER_SWITCH_SARGABLE_CASEFOLD (1ULL << 37)
#define OPTIMIZER_SWITCH_MRR_COST_BASED (1ULL << 18)
#define OPTIMIZER_SWITCH_MRR_SORT_KEYS (1ULL << 19)
#define OPTIMIZER_SWITCH_OUTER_JOIN_WITH_CACHE (1ULL << 20)
#define OPTIMIZER_SWITCH_SEMIJOIN_WITH_CACHE (1ULL << 21)
#define OPTIMIZER_SWITCH_JOIN_CACHE_INCREMENTAL (1ULL << 22)
#define OPTIMIZER_SWITCH_JOIN_CACHE_HASHED (1ULL << 23)
#define OPTIMIZER_SWITCH_JOIN_CACHE_BKA (1ULL << 24)
#define OPTIMIZER_SWITCH_OPTIMIZE_JOIN_BUFFER_SIZE (1ULL << 25)
#define OPTIMIZER_SWITCH_TABLE_ELIMINATION (1ULL << 26)
#define OPTIMIZER_SWITCH_EXTENDED_KEYS (1ULL << 27)
#define OPTIMIZER_SWITCH_EXISTS_TO_IN (1ULL << 28)
#define OPTIMIZER_SWITCH_ORDERBY_EQ_PROP (1ULL << 29)
#define OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED (1ULL << 30)
#define OPTIMIZER_SWITCH_SPLIT_MATERIALIZED (1ULL << 31)
#define OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_SUBQUERY (1ULL << 32)
#define OPTIMIZER_SWITCH_USE_ROWID_FILTER (1ULL << 33)
#define OPTIMIZER_SWITCH_COND_PUSHDOWN_FROM_HAVING (1ULL << 34)
#define OPTIMIZER_SWITCH_NOT_NULL_RANGE_SCAN (1ULL << 35)
#define OPTIMIZER_SWITCH_HASH_JOIN_CARDINALITY (1ULL << 36)
#define OPTIMIZER_SWITCH_CSET_NARROWING (1ULL << 37)
#define OPTIMIZER_SWITCH_SARGABLE_CASEFOLD (1ULL << 38)
/*
@@ -208,6 +209,7 @@
OPTIMIZER_SWITCH_SEMIJOIN | \
OPTIMIZER_SWITCH_FIRSTMATCH | \
OPTIMIZER_SWITCH_LOOSE_SCAN | \
OPTIMIZER_SWITCH_DUPSWEEDOUT | \
OPTIMIZER_SWITCH_EXISTS_TO_IN | \
OPTIMIZER_SWITCH_ORDERBY_EQ_PROP | \
OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED | \

View File

@@ -5601,6 +5601,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
DBUG_ENTER("make_join_statistics");
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
@@ -6316,6 +6317,9 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
join->const_tables=const_count;
join->found_const_table_map=found_const_table_map;
if (sj_nests)
join->select_lex->update_available_semijoin_strategies(thd);
if (join->const_tables != join->table_count)
optimize_keyuse(join, keyuse_array);

View File

@@ -805,6 +805,12 @@ public:
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;
};
@@ -825,12 +831,15 @@ class Duplicate_weedout_picker : public Semi_join_strategy_picker
table_map dupsweedout_tables;
bool is_used;
bool disabled; // See comment for Semi_join_strategy_picker::is_disabled()
public:
void set_empty() override
{
dupsweedout_tables= 0;
first_dupsweedout_table= MAX_TABLES;
is_used= FALSE;
disabled= FALSE;
}
void set_from_prev(POSITION *prev) override;
@@ -845,6 +854,9 @@ public:
POSITION *loose_scan_pos) override;
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);
};

View File

@@ -3043,7 +3043,8 @@ export const char *optimizer_switch_names[]=
"index_merge_intersection","index_merge_sort_intersection",
"index_condition_pushdown",
"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_table_scan",
"subquery_cache",

View File

@@ -3447,6 +3447,10 @@ typedef struct st_nested_join
table_map sj_corr_tables;
table_map direct_children_map;
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
plan. This means two things.