diff --git a/mysql-test/include/default_optimizer_switch.inc b/mysql-test/include/default_optimizer_switch.inc index 5790cec4bc1..5260b7a03c9 100644 --- a/mysql-test/include/default_optimizer_switch.inc +++ b/mysql-test/include/default_optimizer_switch.inc @@ -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; diff --git a/mysql-test/main/mysqld--help.result b/mysql-test/main/mysqld--help.result index eec833adb7c..ede16a4f476 100644 --- a/mysql-test/main/mysqld--help.result +++ b/mysql-test/main/mysqld--help.result @@ -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 diff --git a/mysql-test/main/mysqltest_tracking_info.result b/mysql-test/main/mysqltest_tracking_info.result index 39d898f9108..4266e845d34 100644 --- a/mysql-test/main/mysqltest_tracking_info.result +++ b/mysql-test/main/mysqltest_tracking_info.result @@ -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; diff --git a/mysql-test/main/opt_hint_timeout.test b/mysql-test/main/opt_hint_timeout.test index d64db7a319a..0e9b357be28 100644 --- a/mysql-test/main/opt_hint_timeout.test +++ b/mysql-test/main/opt_hint_timeout.test @@ -1,4 +1,6 @@ +--source include/not_embedded.inc --source include/have_sequence.inc + --echo # --echo # MAX_EXECUTION_TIME hint testing --echo # diff --git a/mysql-test/main/opt_hints.test b/mysql-test/main/opt_hints.test index 67511292840..d04a8922496 100644 --- a/mysql-test/main/opt_hints.test +++ b/mysql-test/main/opt_hints.test @@ -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. diff --git a/mysql-test/main/opt_hints_subquery.result b/mysql-test/main/opt_hints_subquery.result new file mode 100644 index 00000000000..72acab8a8d1 --- /dev/null +++ b/mysql-test/main/opt_hints_subquery.result @@ -0,0 +1,1856 @@ +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; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +test.t2 analyze status Engine-independent statistics collected +test.t2 analyze status OK +test.t3 analyze status Engine-independent statistics collected +test.t3 analyze status OK +# Parser tests +# Correct hints (no warnings): +EXPLAIN EXTENDED +SELECT /*+ SEMIJOIN() */ a FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Note 1003 select /*+ SEMIJOIN(@`select#1`) */ `test`.`t1`.`a` AS `a` from `test`.`t1` +EXPLAIN EXTENDED +SELECT /*+ QB_NAME(qb1) SEMIJOIN(@qb1) */ a FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Note 1003 select /*+ QB_NAME(`qb1`) SEMIJOIN(@`qb1`) */ `test`.`t1`.`a` AS `a` from `test`.`t1` +EXPLAIN EXTENDED +SELECT /*+ QB_NAME(qb1) NO_SEMIJOIN(@qb1 firstmatch) */ a FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Note 1003 select /*+ QB_NAME(`qb1`) NO_SEMIJOIN(@`qb1` FIRSTMATCH) */ `test`.`t1`.`a` AS `a` from `test`.`t1` +EXPLAIN EXTENDED +SELECT /*+ QB_NAME(qb1) SEMIJOIN( @qb1 firstmatch, dupsweedout ) */ a FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Note 1003 select /*+ QB_NAME(`qb1`) SEMIJOIN(@`qb1` FIRSTMATCH, DUPSWEEDOUT) */ `test`.`t1`.`a` AS `a` from `test`.`t1` +EXPLAIN EXTENDED +SELECT /*+ NO_SEMIJOIN( FIRSTMATCH, LOOSESCAN,materialization, DUPSWEEDOUT ) */ a FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Note 1003 select /*+ NO_SEMIJOIN(@`select#1` FIRSTMATCH, LOOSESCAN, MATERIALIZATION, DUPSWEEDOUT) */ `test`.`t1`.`a` AS `a` from `test`.`t1` +EXPLAIN EXTENDED +SELECT /*+ QB_NAME(qb2) NO_SEMIJOIN(@qb2 FIRSTMATCH,LOOSESCAN, materialization, DUPSWEEDOUT) */ a FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Note 1003 select /*+ QB_NAME(`qb2`) NO_SEMIJOIN(@`qb2` FIRSTMATCH, LOOSESCAN, MATERIALIZATION, DUPSWEEDOUT) */ `test`.`t1`.`a` AS `a` from `test`.`t1` +set optimizer_switch='derived_merge=off'; +# 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; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY ALL NULL NULL NULL NULL 4 100.00 +2 DERIVED t2 index NULL a 4 NULL 4 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`qb1`) SEMIJOIN(@`select#1` LOOSESCAN) */ `tt`.`a` AS `a` from (/* select#2 */ select /*+ QB_NAME(`qb1`) */ `test`.`t2`.`a` AS `a` from `test`.`t2`) `tt` +EXPLAIN EXTENDED +SELECT /*+ SEMIJOIN()*/ a +FROM (SELECT /*+ SEMIJOIN(loosescan)*/ * FROM t2) AS tt; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY ALL NULL NULL NULL NULL 4 100.00 +2 DERIVED t2 index NULL a 4 NULL 4 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`select#2` LOOSESCAN) SEMIJOIN(@`select#1`) */ `tt`.`a` AS `a` from (/* select#2 */ select `test`.`t2`.`a` AS `a` from `test`.`t2`) `tt` +EXPLAIN EXTENDED +SELECT /*+ SUBQUERY(materialization) */ a FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Note 1003 select /*+ SUBQUERY(@`select#1` MATERIALIZATION) */ `test`.`t1`.`a` AS `a` from `test`.`t1` +EXPLAIN EXTENDED +SELECT /*+ SUBQUERY( INTOEXISTS ) */ a FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Note 1003 select /*+ SUBQUERY(@`select#1` INTOEXISTS) */ `test`.`t1`.`a` AS `a` from `test`.`t1` +EXPLAIN EXTENDED +SELECT /*+ QB_NAME (qb1) SUBQUERY(@qb1 materialization) */ a FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Note 1003 select /*+ QB_NAME(`qb1`) SUBQUERY(@`qb1` MATERIALIZATION) */ `test`.`t1`.`a` AS `a` from `test`.`t1` +# Incorrect hints (warnings) +SELECT /*+ SEMIJOIN(loosescan @qb1) */ a FROM t1; +a +1 +2 +3 +4 +Warnings: +Warning 1064 Optimizer hint syntax error near '@qb1) */ a FROM t1' at line 1 +SELECT /*+ SEMIJOIN(@qb1 @qb2) */ a FROM t1; +a +1 +2 +3 +4 +Warnings: +Warning 1064 Optimizer hint syntax error near '@qb2) */ a FROM t1' at line 1 +SELECT /*+ SEMIJOIN(@qb1 LOOSESCAN,materialization, unknown_strategy) */ a FROM t1; +a +1 +2 +3 +4 +Warnings: +Warning 1064 Optimizer hint syntax error near 'unknown_strategy) */ a FROM t1' at line 1 +SELECT /*+ NO_SEMIJOIN(@qb1, @qb2) */ a FROM t1; +a +1 +2 +3 +4 +Warnings: +Warning 1064 Optimizer hint syntax error near ', @qb2) */ a FROM t1' at line 1 +SELECT /*+ NO_SEMIJOIN(FIRSTMATCH, ,LOOSESCAN, materialization) */ a FROM t1; +a +1 +2 +3 +4 +Warnings: +Warning 1064 Optimizer hint syntax error near ',LOOSESCAN, materialization) */ a FROM t1' at line 1 +SELECT /*+ NO_SEMIJOIN(FIRSTMATCH, @qb2,LOOSESCAN) */ a FROM t1; +a +1 +2 +3 +4 +Warnings: +Warning 1064 Optimizer hint syntax error near '@qb2,LOOSESCAN) */ a FROM t1' at line 1 +SELECT /*+ SUBQUERY(wrong_strat) */ a FROM t1; +a +1 +2 +3 +4 +Warnings: +Warning 1064 Optimizer hint syntax error near 'wrong_strat) */ a FROM t1' at line 1 +SELECT /*+ SUBQUERY(materialization, intoexists) */ a FROM t1; +a +1 +2 +3 +4 +Warnings: +Warning 1064 Optimizer hint syntax error near ', intoexists) */ a FROM t1' at line 1 +SELECT /*+ SUBQUERY(@qb1 materialization) */ a FROM t1; +a +1 +2 +3 +4 +Warnings: +Warning 4207 Query block name `qb1` is not found for SUBQUERY hint +SELECT /*+ SUBQUERY() */ a FROM t1; +a +1 +2 +3 +4 +Warnings: +Warning 1064 Optimizer hint syntax error near ') */ a FROM t1' at line 1 +# Mix of correct and incorrect hints: +EXPLAIN EXTENDED +SELECT /*+ SEMIJOIN(firstmatch ) SEMIJOIN(loosescan @qb1) */ a FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Warning 1064 Optimizer hint syntax error near '@qb1) */ a FROM t1' at line 2 +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` +EXPLAIN EXTENDED +SELECT /*+ NO_SEMIJOIN(@qb1, @qb2) SEMIJOIN()*/ a FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Warning 1064 Optimizer hint syntax error near ', @qb2) SEMIJOIN()*/ a FROM t1' at line 2 +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` +EXPLAIN EXTENDED +SELECT /*+ NO_SEMIJOIN() NO_SEMIJOIN(FIRSTMATCH, @qb2,LOOSESCAN) */ a FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Warning 1064 Optimizer hint syntax error near '@qb2,LOOSESCAN) */ a FROM t1' at line 2 +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` +# Conflicting hints: +EXPLAIN EXTENDED +SELECT /*+ SEMIJOIN() SEMIJOIN(dupsweedout) NO_SEMIJOIN(firstmatch)*/ a FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Warning 4206 Hint SEMIJOIN(DUPSWEEDOUT) is ignored as conflicting/duplicated +Warning 4206 Hint NO_SEMIJOIN(FIRSTMATCH) is ignored as conflicting/duplicated +Note 1003 select /*+ SEMIJOIN(@`select#1`) */ `test`.`t1`.`a` AS `a` from `test`.`t1` +EXPLAIN EXTENDED +SELECT /*+ SEMIJOIN(loosescan,materialization) SEMIJOIN(dupsweedout)*/ a FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Warning 4206 Hint SEMIJOIN(DUPSWEEDOUT) is ignored as conflicting/duplicated +Note 1003 select /*+ SEMIJOIN(@`select#1` LOOSESCAN, MATERIALIZATION) */ `test`.`t1`.`a` AS `a` from `test`.`t1` +EXPLAIN EXTENDED +SELECT /*+ NO_SEMIJOIN(firstmatch,loosescan,materialization) SEMIJOIN() NO_SEMIJOIN()*/ a +FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Warning 4206 Hint SEMIJOIN() is ignored as conflicting/duplicated +Warning 4206 Hint NO_SEMIJOIN() is ignored as conflicting/duplicated +Note 1003 select /*+ NO_SEMIJOIN(@`select#1` FIRSTMATCH, LOOSESCAN, MATERIALIZATION) */ `test`.`t1`.`a` AS `a` from `test`.`t1` +EXPLAIN EXTENDED +SELECT /*+ QB_NAME(qb1) SEMIJOIN(@qb1) SEMIJOIN(loosescan) NO_SEMIJOIN(@qb1 dupsweedout)*/ a +FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Warning 4206 Hint SEMIJOIN(LOOSESCAN) is ignored as conflicting/duplicated +Warning 4206 Hint NO_SEMIJOIN(@`qb1` DUPSWEEDOUT) is ignored as conflicting/duplicated +Note 1003 select /*+ QB_NAME(`qb1`) SEMIJOIN(@`qb1`) */ `test`.`t1`.`a` AS `a` from `test`.`t1` +EXPLAIN EXTENDED SELECT /*+ SEMIJOIN(firstmatch) NO_SEMIJOIN()*/ a FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Warning 4206 Hint NO_SEMIJOIN() is ignored as conflicting/duplicated +Note 1003 select /*+ SEMIJOIN(@`select#1` FIRSTMATCH) */ `test`.`t1`.`a` AS `a` from `test`.`t1` +EXPLAIN EXTENDED +SELECT /*+ SUBQUERY(materialization) SUBQUERY(intoexists)*/ a FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Warning 4206 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated +Note 1003 select /*+ SUBQUERY(@`select#1` MATERIALIZATION) */ `test`.`t1`.`a` AS `a` from `test`.`t1` +EXPLAIN EXTENDED +SELECT /*+ SEMIJOIN() SUBQUERY(materialization) SUBQUERY(intoexists)*/ a FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Warning 4206 Hint SUBQUERY(MATERIALIZATION) is ignored as conflicting/duplicated +Warning 4206 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated +Note 1003 select /*+ SEMIJOIN(@`select#1`) */ `test`.`t1`.`a` AS `a` from `test`.`t1` +EXPLAIN EXTENDED +SELECT /*+ SUBQUERY(materialization) SUBQUERY(intoexists)*/ a FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Warning 4206 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated +Note 1003 select /*+ SUBQUERY(@`select#1` MATERIALIZATION) */ `test`.`t1`.`a` AS `a` from `test`.`t1` +EXPLAIN EXTENDED +SELECT /*+ SUBQUERY(materialization) SUBQUERY(intoexists) SUBQUERY(materialization)*/ a +FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Warning 4206 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated +Warning 4206 Hint SUBQUERY(MATERIALIZATION) is ignored as conflicting/duplicated +Note 1003 select /*+ SUBQUERY(@`select#1` MATERIALIZATION) */ `test`.`t1`.`a` AS `a` from `test`.`t1` +EXPLAIN EXTENDED +SELECT /*+ SUBQUERY(materialization) SEMIJOIN(firstmatch) SUBQUERY(intoexists)*/ a FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Warning 4206 Hint SEMIJOIN(FIRSTMATCH) is ignored as conflicting/duplicated +Warning 4206 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated +Note 1003 select /*+ SUBQUERY(@`select#1` MATERIALIZATION) */ `test`.`t1`.`a` AS `a` from `test`.`t1` +EXPLAIN EXTENDED +SELECT /*+ QB_NAME(qb1) SEMIJOIN(@qb1) SUBQUERY(@qb1 materialization) SUBQUERY(intoexists)*/ a FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Warning 4206 Hint SUBQUERY(@`qb1` MATERIALIZATION) is ignored as conflicting/duplicated +Warning 4206 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated +Note 1003 select /*+ QB_NAME(`qb1`) SEMIJOIN(@`qb1`) */ `test`.`t1`.`a` AS `a` from `test`.`t1` +EXPLAIN EXTENDED +SELECT /*+ QB_NAME(qb1) SUBQUERY(@qb1 materialization) SEMIJOIN(@qb1 firstmatch) SUBQUERY(intoexists)*/ a FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Warning 4206 Hint SEMIJOIN(@`qb1` FIRSTMATCH) is ignored as conflicting/duplicated +Warning 4206 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated +Note 1003 select /*+ QB_NAME(`qb1`) SUBQUERY(@`qb1` MATERIALIZATION) */ `test`.`t1`.`a` AS `a` from `test`.`t1` +EXPLAIN EXTENDED +SELECT /*+ SEMIJOIN(@qb1) SEMIJOIN(loosescan) NO_SEMIJOIN(@qb1 dupsweedout)*/ a +FROM (SELECT /*+ QB_NAME(qb1)*/ * FROM t2) AS tt; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY ALL NULL NULL NULL NULL 4 100.00 +2 DERIVED t2 index NULL a 4 NULL 4 100.00 Using index +Warnings: +Warning 4206 Hint NO_SEMIJOIN(@`qb1` DUPSWEEDOUT) is ignored as conflicting/duplicated +Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`qb1`) SEMIJOIN(@`select#1` LOOSESCAN) */ `tt`.`a` AS `a` from (/* select#2 */ select /*+ QB_NAME(`qb1`) */ `test`.`t2`.`a` AS `a` from `test`.`t2`) `tt` +DROP TABLE t1, t2 ,t3; +set optimizer_switch=default; +# 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; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +test.t2 analyze status Engine-independent statistics collected +test.t2 analyze status OK +test.t3 analyze status Engine-independent statistics collected +test.t3 analyze status OK +# This query will normally use Table Pull-out +EXPLAIN EXTENDED +SELECT * FROM t2 WHERE t2.a IN (SELECT a FROM t1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 index PRIMARY PRIMARY 4 NULL 4 100.00 Using index +1 PRIMARY t2 ref a a 4 test.t1.a 1 100.00 Using index +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t1` join `test`.`t2` where `test`.`t2`.`a` = `test`.`t1`.`a` +# Check that we can disable SEMIJOIN transformation +EXPLAIN EXTENDED +SELECT * FROM t2 WHERE t2.a IN (SELECT /*+ NO_SEMIJOIN() */ a FROM t1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index +2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`select#2`) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,(((`test`.`t2`.`a`) in t1 on PRIMARY)))) +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index +2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq`) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,(((`test`.`t2`.`a`) in t1 on PRIMARY)))) +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL a NULL NULL NULL 4 100.00 Using where +1 PRIMARY tx eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 Using index +1 PRIMARY ty eq_ref PRIMARY PRIMARY 4 test.t3.b 1 100.00 Using index +Warnings: +Note 1003 select `test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t1` `ty` join `test`.`t1` `tx` join `test`.`t3` where `test`.`tx`.`a` = `test`.`t3`.`a` and `test`.`ty`.`a` = `test`.`t3`.`b` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 4 100.00 Using where +1 PRIMARY ty eq_ref PRIMARY PRIMARY 4 test.t3.b 1 100.00 Using index +2 DEPENDENT SUBQUERY tx unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`select#2`) */ `test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t1` `ty` join `test`.`t3` where `test`.`ty`.`a` = `test`.`t3`.`b` and <`test`.`t3`.`a`>((`test`.`t3`.`a`,(((`test`.`t3`.`a`) in t1 on PRIMARY)))) +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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 4 100.00 Using where +1 PRIMARY ty eq_ref PRIMARY PRIMARY 4 test.t3.b 1 100.00 Using index +2 DEPENDENT SUBQUERY tx unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq1`) */ `test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t1` `ty` join `test`.`t3` where `test`.`ty`.`a` = `test`.`t3`.`b` and <`test`.`t3`.`a`>((`test`.`t3`.`a`,(((`test`.`t3`.`a`) in t1 on PRIMARY)))) +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL a NULL NULL NULL 4 100.00 Using where +1 PRIMARY tx eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 Using index +3 DEPENDENT SUBQUERY ty unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`select#3`) */ `test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t1` `tx` join `test`.`t3` where `test`.`tx`.`a` = `test`.`t3`.`a` and <`test`.`t3`.`b`>((`test`.`t3`.`b`,(((`test`.`t3`.`b`) in t1 on PRIMARY)))) +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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL a NULL NULL NULL 4 100.00 Using where +1 PRIMARY tx eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 Using index +3 DEPENDENT SUBQUERY ty unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq2`) */ `test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t1` `tx` join `test`.`t3` where `test`.`tx`.`a` = `test`.`t3`.`a` and <`test`.`t3`.`b`>((`test`.`t3`.`b`,(((`test`.`t3`.`b`) in t1 on PRIMARY)))) +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 4 100.00 Using where +3 DEPENDENT SUBQUERY ty unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +2 DEPENDENT SUBQUERY tx unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`select#2`) NO_SEMIJOIN(@`select#3`) */ `test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t3` where <`test`.`t3`.`a`>((`test`.`t3`.`a`,(((`test`.`t3`.`a`) in t1 on PRIMARY)))) and <`test`.`t3`.`b`>((`test`.`t3`.`b`,(((`test`.`t3`.`b`) in t1 on PRIMARY)))) +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); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 4 Using where +3 DEPENDENT SUBQUERY ty unique_subquery PRIMARY PRIMARY 4 func 1 Using index +2 DEPENDENT SUBQUERY tx unique_subquery PRIMARY PRIMARY 4 func 1 Using index +# 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)); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL a NULL NULL NULL 4 100.00 +1 PRIMARY tx eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 Using where +1 PRIMARY ty eq_ref PRIMARY PRIMARY 4 test.tx.b 1 100.00 Using index +Warnings: +Note 1003 select `test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t1` `ty` join `test`.`t1` `tx` join `test`.`t3` where `test`.`ty`.`a` = `test`.`tx`.`b` and `test`.`tx`.`a` = `test`.`t3`.`a` +# 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)); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 4 100.00 Using where +2 DEPENDENT SUBQUERY tx eq_ref PRIMARY PRIMARY 4 func 1 100.00 Using where +2 DEPENDENT SUBQUERY ty eq_ref PRIMARY PRIMARY 4 test.tx.b 1 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq1`) */ `test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t3` where <`test`.`t3`.`a`>((`test`.`t3`.`a`,(/* select#2 */ select /*+ QB_NAME(`subq1`) */ `test`.`tx`.`a` from `test`.`t1` `ty` join `test`.`t1` `tx` where `test`.`ty`.`a` = `test`.`tx`.`b` and (`test`.`t3`.`a`) = `test`.`tx`.`a`))) +# 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)); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL a NULL NULL NULL 4 100.00 +1 PRIMARY tx eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 Using where +3 DEPENDENT SUBQUERY ty unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq2`) */ `test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t1` `tx` join `test`.`t3` where `test`.`tx`.`a` = `test`.`t3`.`a` and <`test`.`tx`.`b`>((`test`.`tx`.`b`,(((`test`.`tx`.`b`) in t1 on PRIMARY)))) +# 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)); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 4 100.00 Using where +2 DEPENDENT SUBQUERY tx unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using where +3 DEPENDENT SUBQUERY ty unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq2`) NO_SEMIJOIN(@`subq1`) */ `test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t3` where <`test`.`t3`.`a`>((`test`.`t3`.`a`,(((`test`.`t3`.`a`) in t1 on PRIMARY where (`test`.`tx`.`b`,(((`test`.`tx`.`b`) in t1 on PRIMARY))) and (`test`.`t3`.`a`) = `test`.`tx`.`a`)))) +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY ALL distinct_key NULL NULL NULL 4 100.00 +1 PRIMARY t2 ref a a 4 .min(a) 1 100.00 Using index +2 MATERIALIZED t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`subq`) */ `test`.`t2`.`a` AS `a` from (/* select#2 */ select /*+ QB_NAME(`subq`) */ min(`test`.`t1`.`a`) from `test`.`t1` group by `test`.`t1`.`a`) join `test`.`t2` where `test`.`t2`.`a` = ``.`min(a)` +# This query will get LooseScan by default +EXPLAIN EXTENDED +SELECT * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; LooseScan +1 PRIMARY t2 ref a a 4 test.t3.a 1 25.00 Using index +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where `test`.`t2`.`a` = `test`.`t3`.`a` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index a a 4 NULL 6 100.00 Using index +1 PRIMARY t3 ref a a 4 test.t2.a 1 100.00 Using index; FirstMatch(t2) +Warnings: +Note 1003 select /*+ NO_SEMIJOIN(@`subq1` LOOSESCAN) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where `test`.`t3`.`a` = `test`.`t2`.`a` +# Let's also turn off FirstMatch, DupsWeedout is then used. +# (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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; Start temporary +1 PRIMARY t2 ref a a 4 test.t3.a 1 25.00 Using index; End temporary +Warnings: +Note 1003 select /*+ NO_SEMIJOIN(@`subq1` FIRSTMATCH, LOOSESCAN) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where `test`.`t2`.`a` = `test`.`t3`.`a` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index a a 4 NULL 6 100.00 Using index +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 100.00 +2 MATERIALIZED t3 index a a 4 NULL 4 100.00 Using index +Warnings: +Note 1003 select /*+ NO_SEMIJOIN(@`subq1` FIRSTMATCH, LOOSESCAN, DUPSWEEDOUT) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where 1 +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; Start temporary +1 PRIMARY t2 ref a a 4 test.t3.a 1 25.00 Using index; End temporary +Warnings: +Note 1003 select /*+ NO_SEMIJOIN(@`subq1` FIRSTMATCH, LOOSESCAN, MATERIALIZATION, DUPSWEEDOUT) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where `test`.`t2`.`a` = `test`.`t3`.`a` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; LooseScan +1 PRIMARY t2 ref a a 4 test.t3.a 1 25.00 Using index +Warnings: +Note 1003 select /*+ NO_SEMIJOIN(@`subq1` FIRSTMATCH, MATERIALIZATION, DUPSWEEDOUT) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where `test`.`t2`.`a` = `test`.`t3`.`a` +# Test same query with SEMIJOIN hint +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; LooseScan +1 PRIMARY t2 ref a a 4 test.t3.a 1 25.00 Using index +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` LOOSESCAN) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where `test`.`t2`.`a` = `test`.`t3`.`a` +# Force FirstMatch +EXPLAIN EXTENDED +SELECT /*+ SEMIJOIN(@subq1 FIRSTMATCH) */ * FROM t2 +WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index a a 4 NULL 6 100.00 Using index +1 PRIMARY t3 ref a a 4 test.t2.a 1 100.00 Using index; FirstMatch(t2) +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` FIRSTMATCH) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where `test`.`t3`.`a` = `test`.`t2`.`a` +# Force Materialization +EXPLAIN EXTENDED +SELECT /*+ SEMIJOIN(@subq1 MATERIALIZATION) */ * FROM t2 +WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index a a 4 NULL 6 100.00 Using index +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 100.00 +2 MATERIALIZED t3 index a a 4 NULL 4 100.00 Using index +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` MATERIALIZATION) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where 1 +# Force DuplicateWeedout +EXPLAIN EXTENDED +SELECT /*+ SEMIJOIN(@subq1 DUPSWEEDOUT) */ * FROM t2 +WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; Start temporary +1 PRIMARY t2 ref a a 4 test.t3.a 1 25.00 Using index; End temporary +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` DUPSWEEDOUT) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where `test`.`t2`.`a` = `test`.`t3`.`a` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; LooseScan +1 PRIMARY t2 ref a a 4 test.t3.a 1 25.00 Using index +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` LOOSESCAN, DUPSWEEDOUT) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where `test`.`t2`.`a` = `test`.`t3`.`a` +EXPLAIN EXTENDED +SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN, MATERIALIZATION, DUPSWEEDOUT) */ * FROM t2 +WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; LooseScan +1 PRIMARY t2 ref a a 4 test.t3.a 1 25.00 Using index +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` LOOSESCAN, MATERIALIZATION, DUPSWEEDOUT) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where `test`.`t2`.`a` = `test`.`t3`.`a` +EXPLAIN EXTENDED +SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN, FIRSTMATCH, MATERIALIZATION, +DUPSWEEDOUT) */ * FROM t2 +WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; LooseScan +1 PRIMARY t2 ref a a 4 test.t3.a 1 25.00 Using index +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` LOOSESCAN, FIRSTMATCH, MATERIALIZATION, DUPSWEEDOUT) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where `test`.`t2`.`a` = `test`.`t3`.`a` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index a a 4 NULL 6 100.00 Using index +1 PRIMARY t3 ref a a 4 test.t2.a 1 100.00 Using index; FirstMatch(t2) +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` FIRSTMATCH, MATERIALIZATION, DUPSWEEDOUT) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where `test`.`t3`.`a` = `test`.`t2`.`a` +For this query LooseScan and Materialization is not applicable +EXPLAIN EXTENDED +SELECT * FROM t1 +WHERE t1.b IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3 WHERE t3.b = t1.a); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 4 100.00 Using where +1 PRIMARY t3 ref a a 4 test.t1.b 1 100.00 Using where; FirstMatch(t1) +Warnings: +Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1 +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) where `test`.`t3`.`b` = `test`.`t1`.`a` and `test`.`t3`.`a` = `test`.`t1`.`b` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL a NULL NULL NULL 4 100.00 Using where; Start temporary +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.b 1 25.00 Using where; End temporary +Warnings: +Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1 +Note 1003 select /*+ NO_SEMIJOIN(@`subq1` FIRSTMATCH, DUPSWEEDOUT) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) where `test`.`t1`.`a` = `test`.`t3`.`b` and `test`.`t1`.`b` = `test`.`t3`.`a` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL a NULL NULL NULL 4 100.00 Using where; Start temporary +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.b 1 25.00 Using where; End temporary +Warnings: +Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1 +Note 1003 select /*+ SEMIJOIN(@`subq1` LOOSESCAN, MATERIALIZATION) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) where `test`.`t1`.`a` = `test`.`t3`.`b` and `test`.`t1`.`b` = `test`.`t3`.`a` +# Test multiple subqueries. +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; LooseScan +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.a 1 25.00 Using where +1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; FirstMatch(t1) +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t1`.`a` = `test`.`t3`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; LooseScan +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.a 1 25.00 Using where +1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; FirstMatch(t1) +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` LOOSESCAN) SEMIJOIN(@`subq2` FIRSTMATCH) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t1`.`a` = `test`.`t3`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 4 100.00 Using where +1 PRIMARY t3 ref a a 4 test.t1.a 1 100.00 Using index; FirstMatch(t1) +1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; FirstMatch(t3) +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` FIRSTMATCH) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t3`.`a` = `test`.`t1`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 4 100.00 Using where +1 PRIMARY t3 ref a a 4 test.t1.a 1 100.00 Using index; FirstMatch(t1) +1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; FirstMatch(t3) +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` FIRSTMATCH) SEMIJOIN(@`subq2` FIRSTMATCH) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t3`.`a` = `test`.`t1`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; LooseScan +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.a 1 25.00 Using where +1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; Start temporary; End temporary +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` LOOSESCAN) SEMIJOIN(@`subq2` LOOSESCAN) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t1`.`a` = `test`.`t3`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 4 100.00 Using where +1 PRIMARY t3 ref a a 4 test.t1.a 1 100.00 Using index; FirstMatch(t1) +1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; Start temporary; End temporary +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` FIRSTMATCH) SEMIJOIN(@`subq2` LOOSESCAN) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t3`.`a` = `test`.`t1`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; LooseScan +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.a 1 25.00 Using where +1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; Start temporary; End temporary +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` FIRSTMATCH, LOOSESCAN) SEMIJOIN(@`subq2` MATERIALIZATION, DUPSWEEDOUT) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t1`.`a` = `test`.`t3`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; Start temporary +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.a 1 25.00 Using where; End temporary +1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; FirstMatch(t1) +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` MATERIALIZATION, DUPSWEEDOUT) SEMIJOIN(@`subq2` FIRSTMATCH, LOOSESCAN) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t1`.`a` = `test`.`t3`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 4 100.00 Using where +1 PRIMARY t3 ref a a 4 test.t1.a 1 100.00 Using index; FirstMatch(t1) +1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; Start temporary; End temporary +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` MATERIALIZATION, FIRSTMATCH) SEMIJOIN(@`subq2` LOOSESCAN, DUPSWEEDOUT) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t3`.`a` = `test`.`t1`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 4 100.00 Using where +1 PRIMARY t3 ref a a 4 test.t1.a 1 100.00 Using index; FirstMatch(t1) +1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; Start temporary; End temporary +Warnings: +Note 1003 select /*+ NO_SEMIJOIN(@`subq1` LOOSESCAN) NO_SEMIJOIN(@`subq2` FIRSTMATCH) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t3`.`a` = `test`.`t1`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; Start temporary +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.a 1 25.00 Using where; End temporary +1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; Start temporary; End temporary +Warnings: +Note 1003 select /*+ NO_SEMIJOIN(@`subq1` LOOSESCAN, FIRSTMATCH) NO_SEMIJOIN(@`subq2` FIRSTMATCH, LOOSESCAN) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t1`.`a` = `test`.`t3`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 4 100.00 +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 100.00 +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 100.00 +2 MATERIALIZED t3 index a a 4 NULL 4 100.00 Using index +3 MATERIALIZED t2 index a a 4 NULL 6 100.00 Using index +Warnings: +Note 1003 select /*+ NO_SEMIJOIN(@`subq1` LOOSESCAN, FIRSTMATCH, DUPSWEEDOUT) NO_SEMIJOIN(@`subq2` FIRSTMATCH, LOOSESCAN, DUPSWEEDOUT) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where 1 +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 4 100.00 +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 100.00 +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 100.00 +2 MATERIALIZED t3 index a a 4 NULL 4 100.00 Using index +3 MATERIALIZED t2 index a a 4 NULL 6 100.00 Using index +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` MATERIALIZATION) SEMIJOIN(@`subq2` MATERIALIZATION) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where 1 +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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 4 100.00 Using where +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 100.00 +1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; Start temporary; End temporary +2 MATERIALIZED t3 index a a 4 NULL 4 100.00 Using index +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` MATERIALIZATION) SEMIJOIN(@`subq2` DUPSWEEDOUT) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t2`.`a` = `test`.`t1`.`b` +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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 4 100.00 Using where +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 100.00 +1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; FirstMatch((sj-nest)) +2 MATERIALIZED t3 index a a 4 NULL 4 100.00 Using index +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` MATERIALIZATION) SEMIJOIN(@`subq2` LOOSESCAN, FIRSTMATCH, DUPSWEEDOUT) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t2`.`a` = `test`.`t1`.`b` +# 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)); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 4 100.00 +1 PRIMARY t3 ref a a 4 test.t1.a 1 100.00 Using where +1 PRIMARY t2 ref a a 4 test.t3.b 1 66.67 Using index; FirstMatch(t1) +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t2` join `test`.`t3`) where `test`.`t2`.`a` = `test`.`t3`.`b` and `test`.`t3`.`a` = `test`.`t1`.`a` +# 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)); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL a NULL NULL NULL 4 100.00 Using where; Start temporary +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 +1 PRIMARY t2 ref a a 4 test.t3.b 1 16.67 Using index; End temporary +Warnings: +Note 1003 select /*+ NO_SEMIJOIN(@`subq1` FIRSTMATCH) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t2` join `test`.`t3`) where `test`.`t2`.`a` = `test`.`t3`.`b` and `test`.`t1`.`a` = `test`.`t3`.`a` +# 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)); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t3 ALL a NULL NULL NULL 4 Using where; Start temporary +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.a 1 +1 PRIMARY t2 ref a a 4 test.t3.b 1 Using index; End temporary +# Test the same query with SEMIJOIN hint +# 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)); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 4 100.00 +1 PRIMARY t3 ref a a 4 test.t1.a 1 100.00 Using where +1 PRIMARY t2 ref a a 4 test.t3.b 1 66.67 Using index; FirstMatch(t1) +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` FIRSTMATCH) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t2` join `test`.`t3`) where `test`.`t2`.`a` = `test`.`t3`.`b` and `test`.`t3`.`a` = `test`.`t1`.`a` +# 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)); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL a NULL NULL NULL 4 100.00 Using where; Start temporary +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 +1 PRIMARY t2 ref a a 4 test.t3.b 1 16.67 Using index; End temporary +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` LOOSESCAN) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t2` join `test`.`t3`) where `test`.`t2`.`a` = `test`.`t3`.`b` and `test`.`t1`.`a` = `test`.`t3`.`a` +# 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)); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL a NULL NULL NULL 4 100.00 Using where; Start temporary +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 +1 PRIMARY t2 ref a a 4 test.t3.b 1 16.67 Using index; End temporary +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` DUPSWEEDOUT) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t2` join `test`.`t3`) where `test`.`t2`.`a` = `test`.`t3`.`b` and `test`.`t1`.`a` = `test`.`t3`.`a` +# 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)); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 4 100.00 +1 PRIMARY t3 ref a a 4 test.t1.a 1 100.00 Using where +1 PRIMARY t2 ref a a 4 test.t3.b 1 66.67 Using index; FirstMatch(t1) +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` FIRSTMATCH, DUPSWEEDOUT) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t2` join `test`.`t3`) where `test`.`t2`.`a` = `test`.`t3`.`b` and `test`.`t3`.`a` = `test`.`t1`.`a` +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)); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 4 100.00 +1 PRIMARY t3 ref a a 4 test.t1.a 1 100.00 Using where +1 PRIMARY t2 ref a a 4 test.t3.b 1 66.67 Using index; FirstMatch(t1) +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` MATERIALIZATION, FIRSTMATCH, LOOSESCAN, DUPSWEEDOUT) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t2` join `test`.`t3`) where `test`.`t2`.`a` = `test`.`t3`.`b` and `test`.`t3`.`a` = `test`.`t1`.`a` +# 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; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; Start temporary +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.a 1 25.00 Using where; End temporary +1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; Start temporary; End temporary +Warnings: +Note 1003 select /*+ NO_SEMIJOIN(@`subq1` FIRSTMATCH, LOOSESCAN) NO_SEMIJOIN(@`subq2` FIRSTMATCH, LOOSESCAN) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t1`.`a` = `test`.`t3`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b` +EXECUTE stmt1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; Start temporary +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.a 1 25.00 Using where; End temporary +1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; Start temporary; End temporary +Warnings: +Note 1003 select /*+ NO_SEMIJOIN(@`subq1` FIRSTMATCH, LOOSESCAN) NO_SEMIJOIN(@`subq2` FIRSTMATCH, LOOSESCAN) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t1`.`a` = `test`.`t3`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b` +DEALLOCATE PREPARE stmt1; +SET optimizer_switch = default; +# Tests with non-default optimizer_switch settings +SET optimizer_switch = 'semijoin=off'; +# No table pull-out for this query +EXPLAIN EXTENDED +SELECT * FROM t2 WHERE t2.a IN (SELECT a FROM t1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index +2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,(((`test`.`t2`.`a`) in t1 on PRIMARY)))) +# This should not change anything +EXPLAIN EXTENDED +SELECT /*+ NO_SEMIJOIN(@subq) */ * FROM t2 +WHERE t2.a IN (SELECT /*+ QB_NAME(subq) */ a FROM t1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index +2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq`) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,(((`test`.`t2`.`a`) in t1 on PRIMARY)))) +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 index PRIMARY PRIMARY 4 NULL 4 100.00 Using index +1 PRIMARY t2 ref a a 4 test.t1.a 1 100.00 Using index +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq`) */ `test`.`t2`.`a` AS `a` from `test`.`t1` join `test`.`t2` where `test`.`t2`.`a` = `test`.`t1`.`a` +# Setting strategy should still force semijoin +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 index PRIMARY PRIMARY 4 NULL 4 100.00 Using index +1 PRIMARY t2 ref a a 4 test.t1.a 1 100.00 Using index +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq` FIRSTMATCH) */ `test`.`t2`.`a` AS `a` from `test`.`t1` join `test`.`t2` where `test`.`t2`.`a` = `test`.`t1`.`a` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 4 100.00 Using where +3 DEPENDENT SUBQUERY ty unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +2 DEPENDENT SUBQUERY tx unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select `test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t3` where <`test`.`t3`.`a`>((`test`.`t3`.`a`,(((`test`.`t3`.`a`) in t1 on PRIMARY)))) and <`test`.`t3`.`b`>((`test`.`t3`.`b`,(((`test`.`t3`.`b`) in t1 on PRIMARY)))) +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL a NULL NULL NULL 4 100.00 Using where +1 PRIMARY tx eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 Using index +3 DEPENDENT SUBQUERY ty unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`subq1`) */ `test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t1` `tx` join `test`.`t3` where `test`.`tx`.`a` = `test`.`t3`.`a` and <`test`.`t3`.`b`>((`test`.`t3`.`b`,(((`test`.`t3`.`b`) in t1 on PRIMARY)))) +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 4 100.00 Using where +1 PRIMARY ty eq_ref PRIMARY PRIMARY 4 test.t3.b 1 100.00 Using index +2 DEPENDENT SUBQUERY tx unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`subq2`) */ `test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t1` `ty` join `test`.`t3` where `test`.`ty`.`a` = `test`.`t3`.`b` and <`test`.`t3`.`a`>((`test`.`t3`.`a`,(((`test`.`t3`.`a`) in t1 on PRIMARY)))) +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL a NULL NULL NULL 4 100.00 Using where +1 PRIMARY tx eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 Using index +1 PRIMARY ty eq_ref PRIMARY PRIMARY 4 test.t3.b 1 100.00 Using index +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1`) SEMIJOIN(@`subq2`) */ `test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t1` `ty` join `test`.`t1` `tx` join `test`.`t3` where `test`.`tx`.`a` = `test`.`t3`.`a` and `test`.`ty`.`a` = `test`.`t3`.`b` +# 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)); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 4 100.00 Using where +2 DEPENDENT SUBQUERY tx unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using where +3 DEPENDENT SUBQUERY ty unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select `test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t3` where <`test`.`t3`.`a`>((`test`.`t3`.`a`,(((`test`.`t3`.`a`) in t1 on PRIMARY where (`test`.`tx`.`b`,(((`test`.`tx`.`b`) in t1 on PRIMARY))) and (`test`.`t3`.`a`) = `test`.`tx`.`a`)))) +# 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)); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL a NULL NULL NULL 4 100.00 +1 PRIMARY tx eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 Using where +3 DEPENDENT SUBQUERY ty unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`subq1`) */ `test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t1` `tx` join `test`.`t3` where `test`.`tx`.`a` = `test`.`t3`.`a` and <`test`.`tx`.`b`>((`test`.`tx`.`b`,(((`test`.`tx`.`b`) in t1 on PRIMARY)))) +# 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)); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 4 100.00 Using where +2 DEPENDENT SUBQUERY tx eq_ref PRIMARY PRIMARY 4 func 1 100.00 Using where +2 DEPENDENT SUBQUERY ty eq_ref PRIMARY PRIMARY 4 test.tx.b 1 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`subq2`) */ `test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t3` where <`test`.`t3`.`a`>((`test`.`t3`.`a`,(/* select#2 */ select /*+ QB_NAME(`subq1`) */ `test`.`tx`.`a` from `test`.`t1` `ty` join `test`.`t1` `tx` where `test`.`ty`.`a` = `test`.`tx`.`b` and (`test`.`t3`.`a`) = `test`.`tx`.`a`))) +# 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)); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL a NULL NULL NULL 4 100.00 +1 PRIMARY tx eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 Using where +1 PRIMARY ty eq_ref PRIMARY PRIMARY 4 test.tx.b 1 100.00 Using index +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq2`) SEMIJOIN(@`subq1`) */ `test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t1` `ty` join `test`.`t1` `tx` join `test`.`t3` where `test`.`ty`.`a` = `test`.`tx`.`b` and `test`.`tx`.`a` = `test`.`t3`.`a` +Test strategies when some are disabled by optimizer_switch +SET optimizer_switch='semijoin=on'; +SET optimizer_switch='loosescan=off'; +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index a a 4 NULL 6 100.00 Using index +1 PRIMARY t3 ref a a 4 test.t2.a 1 100.00 Using index; FirstMatch(t2) +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where `test`.`t3`.`a` = `test`.`t2`.`a` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index a a 4 NULL 6 100.00 Using index +1 PRIMARY t3 ref a a 4 test.t2.a 1 100.00 Using index; FirstMatch(t2) +Warnings: +Note 1003 select /*+ NO_SEMIJOIN(@`subq1` LOOSESCAN) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where `test`.`t3`.`a` = `test`.`t2`.`a` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; Start temporary +1 PRIMARY t2 ref a a 4 test.t3.a 1 25.00 Using index; End temporary +Warnings: +Note 1003 select /*+ NO_SEMIJOIN(@`subq1` FIRSTMATCH) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where `test`.`t2`.`a` = `test`.`t3`.`a` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index a a 4 NULL 6 100.00 Using index +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 100.00 +2 MATERIALIZED t3 index a a 4 NULL 4 100.00 Using index +Warnings: +Note 1003 select /*+ NO_SEMIJOIN(@`subq1` FIRSTMATCH, DUPSWEEDOUT) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where 1 +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; LooseScan +1 PRIMARY t2 ref a a 4 test.t3.a 1 25.00 Using index +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` LOOSESCAN) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where `test`.`t2`.`a` = `test`.`t3`.`a` +# Forcing another strategy +EXPLAIN EXTENDED +SELECT /*+ SEMIJOIN(@subq1 MATERIALIZATION) */ * FROM t2 +WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index a a 4 NULL 6 100.00 Using index +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 100.00 +2 MATERIALIZED t3 index a a 4 NULL 4 100.00 Using index +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` MATERIALIZATION) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where 1 +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; LooseScan +1 PRIMARY t2 ref a a 4 test.t3.a 1 25.00 Using index +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` LOOSESCAN, DUPSWEEDOUT) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where `test`.`t2`.`a` = `test`.`t3`.`a` +EXPLAIN EXTENDED +SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN, MATERIALIZATION, DUPSWEEDOUT) */ * FROM t2 +WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; LooseScan +1 PRIMARY t2 ref a a 4 test.t3.a 1 25.00 Using index +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` LOOSESCAN, MATERIALIZATION, DUPSWEEDOUT) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where `test`.`t2`.`a` = `test`.`t3`.`a` +EXPLAIN EXTENDED +SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN, FIRSTMATCH, MATERIALIZATION, +DUPSWEEDOUT) */ * FROM t2 +WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; LooseScan +1 PRIMARY t2 ref a a 4 test.t3.a 1 25.00 Using index +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` LOOSESCAN, FIRSTMATCH, MATERIALIZATION, DUPSWEEDOUT) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where `test`.`t2`.`a` = `test`.`t3`.`a` +Disable another strategy +SET optimizer_switch='firstmatch=off'; +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index a a 4 NULL 6 100.00 Using index +1 PRIMARY t3 ref a a 4 test.t2.a 1 100.00 Using index; FirstMatch(t2) +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` FIRSTMATCH, MATERIALIZATION, DUPSWEEDOUT) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where `test`.`t3`.`a` = `test`.`t2`.`a` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; Start temporary +1 PRIMARY t2 ref a a 4 test.t3.a 1 25.00 Using index; End temporary +Warnings: +Note 1003 select /*+ NO_SEMIJOIN(@`subq1` MATERIALIZATION, DUPSWEEDOUT) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where `test`.`t2`.`a` = `test`.`t3`.`a` +# For this query LooseScan and Materialization is not applicable +# Should use DuplicateWeedout since FirstMatch is disabled +EXPLAIN EXTENDED +SELECT * FROM t1 +WHERE t1.b IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3 WHERE t3.b = t1.a); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL a NULL NULL NULL 4 100.00 Using where; Start temporary +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.b 1 25.00 Using where; End temporary +Warnings: +Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1 +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) where `test`.`t1`.`a` = `test`.`t3`.`b` and `test`.`t1`.`b` = `test`.`t3`.`a` +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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL a NULL NULL NULL 4 100.00 Using where; Start temporary +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.b 1 25.00 Using where; End temporary +Warnings: +Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1 +Note 1003 select /*+ NO_SEMIJOIN(@`subq1` FIRSTMATCH, DUPSWEEDOUT) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) where `test`.`t1`.`a` = `test`.`t3`.`b` and `test`.`t1`.`b` = `test`.`t3`.`a` +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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 4 100.00 Using where +1 PRIMARY t3 ref a a 4 test.t1.b 1 100.00 Using where; FirstMatch(t1) +Warnings: +Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1 +Note 1003 select /*+ SEMIJOIN(@`subq1` LOOSESCAN, FIRSTMATCH) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) where `test`.`t3`.`b` = `test`.`t1`.`a` and `test`.`t3`.`a` = `test`.`t1`.`b` +# Default for this query is Loosecan for first and FirstMatch for latter +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; Start temporary +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.a 1 25.00 Using where; End temporary +1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; Start temporary; End temporary +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t1`.`a` = `test`.`t3`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; LooseScan +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.a 1 25.00 Using where +1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; FirstMatch(t1) +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` LOOSESCAN, FIRSTMATCH) SEMIJOIN(@`subq2` LOOSESCAN, FIRSTMATCH) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t1`.`a` = `test`.`t3`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 4 100.00 Using where +1 PRIMARY t3 ref a a 4 test.t1.a 1 100.00 Using index; FirstMatch(t1) +1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; Start temporary; End temporary +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` FIRSTMATCH) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t3`.`a` = `test`.`t1`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 4 100.00 Using where +1 PRIMARY t3 ref a a 4 test.t1.a 1 100.00 Using index; FirstMatch(t1) +1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; FirstMatch(t3) +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` FIRSTMATCH) SEMIJOIN(@`subq2` FIRSTMATCH) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t3`.`a` = `test`.`t1`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 4 100.00 Using where +1 PRIMARY t3 ref a a 4 test.t1.a 1 100.00 Using index; FirstMatch(t1) +1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; Start temporary; End temporary +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` FIRSTMATCH) SEMIJOIN(@`subq2` LOOSESCAN) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t3`.`a` = `test`.`t1`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; LooseScan +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.a 1 25.00 Using where +1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; Start temporary; End temporary +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` FIRSTMATCH, LOOSESCAN) SEMIJOIN(@`subq2` MATERIALIZATION, DUPSWEEDOUT) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t1`.`a` = `test`.`t3`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 4 100.00 +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 100.00 +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 100.00 +2 MATERIALIZED t3 index a a 4 NULL 4 100.00 Using index +3 MATERIALIZED t2 index a a 4 NULL 6 100.00 Using index +Warnings: +Note 1003 select /*+ NO_SEMIJOIN(@`subq1` DUPSWEEDOUT) NO_SEMIJOIN(@`subq2` DUPSWEEDOUT) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where 1 +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 4 100.00 +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 100.00 +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 100.00 +2 MATERIALIZED t3 index a a 4 NULL 4 100.00 Using index +3 MATERIALIZED t2 index a a 4 NULL 6 100.00 Using index +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` MATERIALIZATION) SEMIJOIN(@`subq2` MATERIALIZATION) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where 1 +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 4 100.00 Using where +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 100.00 +1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; Start temporary; End temporary +2 MATERIALIZED t3 index a a 4 NULL 4 100.00 Using index +Warnings: +Note 1003 select /*+ NO_SEMIJOIN(@`subq1` DUPSWEEDOUT) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t2`.`a` = `test`.`t1`.`b` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; Start temporary +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.a 1 25.00 End temporary +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 100.00 +3 MATERIALIZED t2 index a a 4 NULL 6 100.00 Using index +Warnings: +Note 1003 select /*+ NO_SEMIJOIN(@`subq2` DUPSWEEDOUT) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t1`.`a` = `test`.`t3`.`a` +Enable all strategies except DuplicateWeedout +SET optimizer_switch='firstmatch=on,loosescan=on,materialization=on,duplicateweedout=off'; +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; Start temporary +1 PRIMARY t2 ref a a 4 test.t3.a 1 25.00 Using index; End temporary +Warnings: +Note 1003 select /*+ NO_SEMIJOIN(@`subq1` LOOSESCAN, FIRSTMATCH, MATERIALIZATION) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where `test`.`t2`.`a` = `test`.`t3`.`a` +# LooseScan and Materialization is not applicable, FirstMatch is used +EXPLAIN EXTENDED +SELECT * FROM t1 +WHERE t1.b IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3 WHERE t3.b = t1.a); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 4 100.00 Using where +1 PRIMARY t3 ref a a 4 test.t1.b 1 100.00 Using where; FirstMatch(t1) +Warnings: +Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1 +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) where `test`.`t3`.`b` = `test`.`t1`.`a` and `test`.`t3`.`a` = `test`.`t1`.`b` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL a NULL NULL NULL 4 100.00 Using where; Start temporary +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.b 1 25.00 Using where; End temporary +Warnings: +Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1 +Note 1003 select /*+ NO_SEMIJOIN(@`subq1` FIRSTMATCH) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) where `test`.`t1`.`a` = `test`.`t3`.`b` and `test`.`t1`.`b` = `test`.`t3`.`a` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL a NULL NULL NULL 4 100.00 Using where; Start temporary +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.b 1 25.00 Using where; End temporary +Warnings: +Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1 +Note 1003 select /*+ SEMIJOIN(@`subq1` LOOSESCAN, MATERIALIZATION) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) where `test`.`t1`.`a` = `test`.`t3`.`b` and `test`.`t1`.`b` = `test`.`t3`.`a` +# Disable all strategies +SET optimizer_switch='firstmatch=off,loosescan=off,materialization=off,duplicateweedout=off'; +# DuplicateWeedout is then used +EXPLAIN EXTENDED +SELECT * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; Start temporary +1 PRIMARY t2 ref a a 4 test.t3.a 1 25.00 Using index; End temporary +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where `test`.`t2`.`a` = `test`.`t3`.`a` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; Start temporary +1 PRIMARY t2 ref a a 4 test.t3.a 1 25.00 Using index; End temporary +Warnings: +Note 1003 select /*+ NO_SEMIJOIN(@`subq1` LOOSESCAN, DUPSWEEDOUT) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where `test`.`t2`.`a` = `test`.`t3`.`a` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index a a 4 NULL 6 100.00 Using index +1 PRIMARY t3 ref a a 4 test.t2.a 1 100.00 Using index; FirstMatch(t2) +Warnings: +Note 1003 select /*+ SEMIJOIN(@`subq1` FIRSTMATCH, MATERIALIZATION) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where `test`.`t3`.`a` = `test`.`t2`.`a` +# For this query that cannot use LooseScan or Materialization, +# turning those on will still give DuplicateWeedout +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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL a NULL NULL NULL 4 100.00 Using where; Start temporary +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.b 1 25.00 Using where; End temporary +Warnings: +Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1 +Note 1003 select /*+ SEMIJOIN(@`subq1` LOOSESCAN, MATERIALIZATION) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) where `test`.`t1`.`a` = `test`.`t3`.`b` and `test`.`t1`.`b` = `test`.`t3`.`a` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 4 100.00 Using where +1 PRIMARY t3 ref a a 4 test.t1.b 1 100.00 Using where; FirstMatch(t1) +Warnings: +Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1 +Note 1003 select /*+ SEMIJOIN(@`subq1` LOOSESCAN, FIRSTMATCH) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) where `test`.`t3`.`b` = `test`.`t1`.`a` and `test`.`t3`.`a` = `test`.`t1`.`b` +SET optimizer_switch = default; +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; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; Start temporary +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.a 1 25.00 Using where; End temporary +1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; Start temporary; End temporary +Warnings: +Note 1003 select /*+ NO_SEMIJOIN(@`subq1` FIRSTMATCH, LOOSESCAN) NO_SEMIJOIN(@`subq2` FIRSTMATCH, LOOSESCAN) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t1`.`a` = `test`.`t3`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b` +SET optimizer_switch = 'duplicateweedout=off'; +Will now use materialization +EXECUTE stmt1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 4 100.00 +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 100.00 +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 100.00 +2 MATERIALIZED t3 index a a 4 NULL 4 100.00 Using index +3 MATERIALIZED t2 index a a 4 NULL 6 100.00 Using index +Warnings: +Note 1003 select /*+ NO_SEMIJOIN(@`subq1` FIRSTMATCH, LOOSESCAN) NO_SEMIJOIN(@`subq2` FIRSTMATCH, LOOSESCAN) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where 1 +SET optimizer_switch = 'duplicateweedout=on'; +Turn DuplicateWeedout back on +EXECUTE stmt1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; Start temporary +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.a 1 25.00 Using where; End temporary +1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; Start temporary; End temporary +Warnings: +Note 1003 select /*+ NO_SEMIJOIN(@`subq1` FIRSTMATCH, LOOSESCAN) NO_SEMIJOIN(@`subq2` FIRSTMATCH, LOOSESCAN) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t1`.`a` = `test`.`t3`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b` +DEALLOCATE PREPARE stmt1; +SET optimizer_switch = default; +# Specifying two SEMIJOIN/NO_SEMIJOIN for same query block gives warning +# First has effect, second is ignored +EXPLAIN EXTENDED +SELECT * FROM t2 +WHERE t2.a IN (SELECT /*+ NO_SEMIJOIN() SEMIJOIN() */ a FROM t1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index +2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Warning 4206 Hint SEMIJOIN() is ignored as conflicting/duplicated +Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`select#2`) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,(((`test`.`t2`.`a`) in t1 on PRIMARY)))) +# Try opposite order +EXPLAIN EXTENDED +SELECT * FROM t2 +WHERE t2.a IN (SELECT /*+ SEMIJOIN() NO_SEMIJOIN() */ a FROM t1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 index PRIMARY PRIMARY 4 NULL 4 100.00 Using index +1 PRIMARY t2 ref a a 4 test.t1.a 1 100.00 Using index +Warnings: +Warning 4206 Hint NO_SEMIJOIN() is ignored as conflicting/duplicated +Note 1003 select /*+ SEMIJOIN(@`select#2`) */ `test`.`t2`.`a` AS `a` from `test`.`t1` join `test`.`t2` where `test`.`t2`.`a` = `test`.`t1`.`a` +# Specify at different levels, hint inside block has effect +EXPLAIN EXTENDED +SELECT /*+ NO_SEMIJOIN(@subq) */ * FROM t2 +WHERE t2.a IN (SELECT /*+ QB_NAME(subq) SEMIJOIN() */ a FROM t1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 index PRIMARY PRIMARY 4 NULL 4 100.00 Using index +1 PRIMARY t2 ref a a 4 test.t1.a 1 100.00 Using index +Warnings: +Warning 4206 Hint NO_SEMIJOIN(@`subq` ) is ignored as conflicting/duplicated +Note 1003 select /*+ SEMIJOIN(@`subq`) */ `test`.`t2`.`a` AS `a` from `test`.`t1` join `test`.`t2` where `test`.`t2`.`a` = `test`.`t1`.`a` +# Specify at different levels, opposite order +EXPLAIN EXTENDED +SELECT /*+ SEMIJOIN(@subq) */ * FROM t2 +WHERE t2.a IN (SELECT /*+ QB_NAME(subq) NO_SEMIJOIN() */ a FROM t1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index +2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Warning 4206 Hint SEMIJOIN(@`subq` ) is ignored as conflicting/duplicated +Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq`) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,(((`test`.`t2`.`a`) in t1 on PRIMARY)))) +# Duplicate hints also gives warning, but hint has effect +EXPLAIN EXTENDED +SELECT /*+ SEMIJOIN(@subq) */ * FROM t2 +WHERE t2.a IN (SELECT /*+ QB_NAME(subq) SEMIJOIN() */ a FROM t1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 index PRIMARY PRIMARY 4 NULL 4 100.00 Using index +1 PRIMARY t2 ref a a 4 test.t1.a 1 100.00 Using index +Warnings: +Warning 4206 Hint SEMIJOIN(@`subq` ) is ignored as conflicting/duplicated +Note 1003 select /*+ SEMIJOIN(@`subq`) */ `test`.`t2`.`a` AS `a` from `test`.`t1` join `test`.`t2` where `test`.`t2`.`a` = `test`.`t1`.`a` +EXPLAIN EXTENDED +SELECT /*+ NO_SEMIJOIN(@subq) */ * FROM t2 +WHERE t2.a IN (SELECT /*+ QB_NAME(subq) NO_SEMIJOIN() */ a FROM t1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index +2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Warning 4206 Hint NO_SEMIJOIN(@`subq` ) is ignored as conflicting/duplicated +Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq`) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,(((`test`.`t2`.`a`) in t1 on PRIMARY)))) +# Multiple subqueries with conflicting hints +EXPLAIN EXTENDED +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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 100.00 Using where +1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; Start temporary; End temporary +2 DEPENDENT SUBQUERY t3 index_subquery a a 4 func 1 100.00 Using index +Warnings: +Warning 4206 Hint SEMIJOIN(@`subq1` LOOSESCAN) is ignored as conflicting/duplicated +Warning 4206 Hint SEMIJOIN(@`subq2` FIRSTMATCH) is ignored as conflicting/duplicated +Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq1`) SEMIJOIN(@`subq2` LOOSESCAN) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t2`) where `test`.`t2`.`a` = `test`.`t1`.`b` and <`test`.`t1`.`a`>((`test`.`t1`.`a`,(((`test`.`t1`.`a`) in t3 on a)))) +EXPLAIN EXTENDED +SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN) SEMIJOIN(@subq2 FIRSTMATCH) */ * FROM t1 +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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 4 100.00 Using where +1 PRIMARY t3 ref a a 4 test.t1.a 1 100.00 Using index; FirstMatch(t1) +1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; Start temporary; End temporary +Warnings: +Warning 4206 Hint SEMIJOIN(@`subq1` LOOSESCAN) is ignored as conflicting/duplicated +Warning 4206 Hint SEMIJOIN(@`subq2` FIRSTMATCH) is ignored as conflicting/duplicated +Note 1003 select /*+ NO_SEMIJOIN(@`subq1` LOOSESCAN) SEMIJOIN(@`subq2` LOOSESCAN) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t3`.`a` = `test`.`t1`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b` +# Conflicting hints in same hint comment +EXPLAIN EXTENDED +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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; LooseScan +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.a 1 25.00 Using where +1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; FirstMatch(t1) +Warnings: +Warning 4206 Hint SEMIJOIN(@`subq1` FIRSTMATCH) is ignored as conflicting/duplicated +Note 1003 select /*+ SEMIJOIN(@`subq1` LOOSESCAN) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t1`.`a` = `test`.`t3`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b` +EXPLAIN EXTENDED +SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN) NO_SEMIJOIN(@subq1 LOOSESCAN) */ * +FROM t1 +WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3) +AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; LooseScan +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.a 1 25.00 Using where +1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; FirstMatch(t1) +Warnings: +Warning 4206 Hint NO_SEMIJOIN(@`subq1` LOOSESCAN) is ignored as conflicting/duplicated +Note 1003 select /*+ SEMIJOIN(@`subq1` LOOSESCAN) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t1`.`a` = `test`.`t3`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b` +EXPLAIN EXTENDED +SELECT /*+ NO_SEMIJOIN(@subq1 LOOSESCAN) NO_SEMIJOIN(@subq1 FIRSTMATCH) */ * +FROM t1 +WHERE t1.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3) +AND t1.b IN (SELECT /*+ QB_NAME(subq2) */ a FROM t2); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 4 100.00 Using where +1 PRIMARY t3 ref a a 4 test.t1.a 1 100.00 Using index; FirstMatch(t1) +1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; FirstMatch(t3) +Warnings: +Warning 4206 Hint NO_SEMIJOIN(@`subq1` FIRSTMATCH) is ignored as conflicting/duplicated +Note 1003 select /*+ NO_SEMIJOIN(@`subq1` LOOSESCAN) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t3`.`a` = `test`.`t1`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b` +# Non-supported strategies should give warnings +EXPLAIN EXTENDED +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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 index a a 4 NULL 4 100.00 Using index; LooseScan +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.a 1 25.00 Using where +1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; FirstMatch(t1) +Warnings: +Warning 1064 Optimizer hint syntax error near 'INTOEXISTS) NO_SEMIJOIN(@subq2 INTOEXISTS) */ * +FROM t1 +WHERE t1.a IN (SELECT...' at line 2 +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t1`.`a` = `test`.`t3`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b` +# SUBQUERY tests +# SUBQUERY should disable SEMIJOIN and use specified subquery strategy +EXPLAIN EXTENDED +SELECT * FROM t2 WHERE t2.a IN (SELECT /*+ SUBQUERY(INTOEXISTS) */ a FROM t1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index +2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select /*+ SUBQUERY(@`select#2` INTOEXISTS) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,(((`test`.`t2`.`a`) in t1 on PRIMARY)))) +EXPLAIN +SELECT /*+ SUBQUERY(@subq MATERIALIZATION) */ * FROM t2 +WHERE t2.a IN (SELECT /*+ QB_NAME(subq) */ a FROM t1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 index NULL a 4 NULL 6 Using where; Using index +2 MATERIALIZED t1 index NULL PRIMARY 4 NULL 4 Using index +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 4 100.00 Using where +3 MATERIALIZED ty index NULL PRIMARY 4 NULL 4 100.00 Using index +2 DEPENDENT SUBQUERY tx unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select /*+ SUBQUERY(@`subq1` INTOEXISTS) SUBQUERY(@`subq2` MATERIALIZATION) */ `test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t3` where <`test`.`t3`.`a`>((`test`.`t3`.`a`,(((`test`.`t3`.`a`) in t1 on PRIMARY)))) and <`test`.`t3`.`b`>((`test`.`t3`.`b`,`test`.`t3`.`b` in ( (/* select#3 */ select /*+ QB_NAME(`subq2`) */ `test`.`ty`.`a` from `test`.`t1` `ty` ), (`test`.`t3`.`b` in on distinct_key where `test`.`t3`.`b` = ``.`a`)))) +# 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)); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 4 100.00 Using where +2 DEPENDENT SUBQUERY tx unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using where +3 MATERIALIZED ty index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select /*+ SUBQUERY(@`subq2` MATERIALIZATION) SUBQUERY(@`subq1` INTOEXISTS) */ `test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t3` where <`test`.`t3`.`a`>((`test`.`t3`.`a`,(((`test`.`t3`.`a`) in t1 on PRIMARY where (`test`.`tx`.`b`,`test`.`tx`.`b` in ( (/* select#3 */ select /*+ QB_NAME(`subq2`) */ `test`.`ty`.`a` from `test`.`t1` `ty` ), (`test`.`tx`.`b` in on distinct_key where `test`.`tx`.`b` = ``.`a`))) and (`test`.`t3`.`a`) = `test`.`tx`.`a`)))) +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)); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 4 100.00 Using where +2 MATERIALIZED tx ALL NULL NULL NULL NULL 4 100.00 Using where +3 DEPENDENT SUBQUERY ty unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select /*+ SUBQUERY(@`subq2` INTOEXISTS) SUBQUERY(@`subq1` MATERIALIZATION) */ `test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t3` where <`test`.`t3`.`a`>((`test`.`t3`.`a`,`test`.`t3`.`a` in ( (/* select#2 */ select /*+ QB_NAME(`subq1`) */ `test`.`tx`.`a` from `test`.`t1` `tx` where <`test`.`tx`.`b`>((`test`.`tx`.`b`,(((`test`.`tx`.`b`) in t1 on PRIMARY)))) ), (`test`.`t3`.`a` in on distinct_key where `test`.`t3`.`a` = ``.`a`)))) +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY ALL distinct_key NULL NULL NULL 4 100.00 +1 PRIMARY t2 ref a a 4 .min(a) 1 100.00 Using index +2 MATERIALIZED t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a` from (/* select#2 */ select /*+ QB_NAME(`subq`) */ min(`test`.`t1`.`a`) from `test`.`t1` group by `test`.`t1`.`a`) join `test`.`t2` where `test`.`t2`.`a` = ``.`min(a)` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index +2 DEPENDENT SUBQUERY t1 index NULL PRIMARY 4 NULL 1 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select /*+ SUBQUERY(@`subq` INTOEXISTS) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,(/* select#2 */ select /*+ QB_NAME(`subq`) */ min(`test`.`t1`.`a`) from `test`.`t1` group by `test`.`t1`.`a` having (`test`.`t2`.`a`) = (min(`test`.`t1`.`a`))))) +# For this query In-to-exists is default +EXPLAIN EXTENDED +SELECT a, a IN (SELECT a FROM t1) FROM t2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using index +2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a`,<`test`.`t2`.`a`>((`test`.`t2`.`a`,(((`test`.`t2`.`a`) in t1 on PRIMARY)))) AS `a IN (SELECT a FROM t1)` from `test`.`t2` +# Force Subquery Materialization +EXPLAIN EXTENDED +SELECT a, a IN (SELECT /*+ SUBQUERY(MATERIALIZATION) */ a FROM t1) FROM t2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using index +2 MATERIALIZED t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select /*+ SUBQUERY(@`select#2` MATERIALIZATION) */ `test`.`t2`.`a` AS `a`,<`test`.`t2`.`a`>((`test`.`t2`.`a`,`test`.`t2`.`a` in ( (/* select#2 */ select `test`.`t1`.`a` from `test`.`t1` ), (`test`.`t2`.`a` in on distinct_key where `test`.`t2`.`a` = ``.`a`)))) AS `a IN (SELECT /*+ SUBQUERY(MATERIALIZATION) */ a FROM t1)` from `test`.`t2` +EXPLAIN EXTENDED +SELECT /*+ SUBQUERY(@subq MATERIALIZATION) */ a, +a IN (SELECT /*+ QB_NAME(subq) */ a FROM t1) FROM t2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using index +2 MATERIALIZED t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select /*+ SUBQUERY(@`subq` MATERIALIZATION) */ `test`.`t2`.`a` AS `a`,<`test`.`t2`.`a`>((`test`.`t2`.`a`,`test`.`t2`.`a` in ( (/* select#2 */ select /*+ QB_NAME(`subq`) */ `test`.`t1`.`a` from `test`.`t1` ), (`test`.`t2`.`a` in on distinct_key where `test`.`t2`.`a` = ``.`a`)))) AS `a IN (SELECT /*+ QB_NAME(subq) */ a FROM t1)` from `test`.`t2` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index +2 DEPENDENT SUBQUERY t1 index NULL PRIMARY 4 NULL 1 100.00 +Warnings: +Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,(/* select#2 */ select /*+ QB_NAME(`subq`) */ sum(`test`.`t1`.`b`) from `test`.`t1` group by `test`.`t1`.`a` having (`test`.`t2`.`a`) = (sum(`test`.`t1`.`b`))))) +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index +2 DEPENDENT SUBQUERY t1 index NULL PRIMARY 4 NULL 1 100.00 +Warnings: +Note 1003 /* select#1 */ select /*+ SUBQUERY(@`subq` MATERIALIZATION) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,(/* select#2 */ select /*+ QB_NAME(`subq`) */ sum(`test`.`t1`.`b`) from `test`.`t1` group by `test`.`t1`.`a` having (`test`.`t2`.`a`) = (sum(`test`.`t1`.`b`))))) +# 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; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where +3 DEPENDENT SUBQUERY t2 index_subquery a a 4 func 1 Using index +2 MATERIALIZED t3 index NULL a 4 NULL 4 Using index +EXECUTE stmt1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where +3 DEPENDENT SUBQUERY t2 index_subquery a a 4 func 1 Using index +2 MATERIALIZED t3 index NULL a 4 NULL 4 Using index +DEALLOCATE PREPARE stmt1; +# Test optimizer_switch settings with SUBQUERY hint +SET optimizer_switch='materialization=off'; +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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index +2 DEPENDENT SUBQUERY t1 index NULL PRIMARY 4 NULL 1 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,(/* select#2 */ select /*+ QB_NAME(`subq`) */ min(`test`.`t1`.`a`) from `test`.`t1` group by `test`.`t1`.`a` having (`test`.`t2`.`a`) = (min(`test`.`t1`.`a`))))) +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index +2 MATERIALIZED t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select /*+ SUBQUERY(@`subq` MATERIALIZATION) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,`test`.`t2`.`a` in ( (/* select#2 */ select /*+ QB_NAME(`subq`) */ min(`test`.`t1`.`a`) from `test`.`t1` group by `test`.`t1`.`a` ), (`test`.`t2`.`a` in on distinct_key where `test`.`t2`.`a` = ``.`min(a)`)))) +SET optimizer_switch='materialization=on'; +# This query will now use In-to_exists +EXPLAIN EXTENDED +SELECT a, a IN (SELECT a FROM t1) FROM t2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using index +2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a`,<`test`.`t2`.`a`>((`test`.`t2`.`a`,(((`test`.`t2`.`a`) in t1 on PRIMARY)))) AS `a IN (SELECT a FROM t1)` from `test`.`t2` +Force Materialization +EXPLAIN EXTENDED +SELECT /*+ SUBQUERY(@subq MATERIALIZATION) */ a, +a IN (SELECT /*+ QB_NAME(subq) */ a FROM t1) FROM t2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using index +2 MATERIALIZED t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select /*+ SUBQUERY(@`subq` MATERIALIZATION) */ `test`.`t2`.`a` AS `a`,<`test`.`t2`.`a`>((`test`.`t2`.`a`,`test`.`t2`.`a` in ( (/* select#2 */ select /*+ QB_NAME(`subq`) */ `test`.`t1`.`a` from `test`.`t1` ), (`test`.`t2`.`a` in on distinct_key where `test`.`t2`.`a` = ``.`a`)))) AS `a IN (SELECT /*+ QB_NAME(subq) */ a FROM t1)` from `test`.`t2` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL a NULL NULL NULL 4 100.00 Using where +1 PRIMARY tx eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 Using index +1 PRIMARY ty eq_ref PRIMARY PRIMARY 4 test.t3.b 1 100.00 Using index +Warnings: +Warning 1064 Optimizer hint syntax error near ', INTOEXISTS) +SUBQUERY(@subq2 MATERIALIZATION, INTOEXISTS) */ * +FROM t3 +WHERE...' at line 2 +Note 1003 select `test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t1` `ty` join `test`.`t1` `tx` join `test`.`t3` where `test`.`tx`.`a` = `test`.`t3`.`a` and `test`.`ty`.`a` = `test`.`t3`.`b` +# 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); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL a NULL NULL NULL 4 100.00 Using where +1 PRIMARY tx eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 Using index +1 PRIMARY ty eq_ref PRIMARY PRIMARY 4 test.t3.b 1 100.00 Using index +Warnings: +Warning 1064 Optimizer hint syntax error near 'FIRSTMATCH) SUBQUERY(@subq2 LOOSESCAN) */ * +FROM t3 +WHERE t3.a IN (SELECT /*+...' at line 2 +Note 1003 select `test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t1` `ty` join `test`.`t1` `tx` join `test`.`t3` where `test`.`tx`.`a` = `test`.`t3`.`a` and `test`.`ty`.`a` = `test`.`t3`.`b` +SET optimizer_switch= default; +# Specifying two SUBQUERY for same query block gives warning +# First has effect, second is ignored +EXPLAIN EXTENDED +SELECT * FROM t2 +WHERE t2.a IN (SELECT /*+ SUBQUERY(MATERIALIZATION) SUBQUERY(INTOEXISTS) */ a +FROM t1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index +2 MATERIALIZED t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Warning 4206 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated +Note 1003 /* select#1 */ select /*+ SUBQUERY(@`select#2` MATERIALIZATION) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,`test`.`t2`.`a` in ( (/* select#2 */ select `test`.`t1`.`a` from `test`.`t1` ), (`test`.`t2`.`a` in on distinct_key where `test`.`t2`.`a` = ``.`a`)))) +# Try opposite order +EXPLAIN EXTENDED +SELECT * FROM t2 +WHERE t2.a IN (SELECT /*+ SUBQUERY(INTOEXISTS) SUBQUERY(MATERIALIZATION) */ a +FROM t1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index +2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Warning 4206 Hint SUBQUERY(MATERIALIZATION) is ignored as conflicting/duplicated +Note 1003 /* select#1 */ select /*+ SUBQUERY(@`select#2` INTOEXISTS) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,(((`test`.`t2`.`a`) in t1 on PRIMARY)))) +# Specify at different levels, hint inside block has effect +EXPLAIN EXTENDED +SELECT /*+ SUBQUERY(@subq MATERIALIZATION) */ * FROM t2 +WHERE t2.a IN (SELECT /*+ QB_NAME(subq) SUBQUERY(INTOEXISTS) */ a FROM t1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index +2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Warning 4206 Hint SUBQUERY(@`subq` MATERIALIZATION) is ignored as conflicting/duplicated +Note 1003 /* select#1 */ select /*+ SUBQUERY(@`subq` INTOEXISTS) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,(((`test`.`t2`.`a`) in t1 on PRIMARY)))) +# Specify at different levels, opposite order +EXPLAIN EXTENDED +SELECT /*+ SUBQUERY(@subq INTOEXISTS) */ * FROM t2 +WHERE t2.a IN (SELECT /*+ QB_NAME(subq) SUBQUERY(MATERIALIZATION) */ a FROM t1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index +2 MATERIALIZED t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +Warnings: +Warning 4206 Hint SUBQUERY(@`subq` INTOEXISTS) is ignored as conflicting/duplicated +Note 1003 /* select#1 */ select /*+ SUBQUERY(@`subq` MATERIALIZATION) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,`test`.`t2`.`a` in ( (/* select#2 */ select /*+ QB_NAME(`subq`) */ `test`.`t1`.`a` from `test`.`t1` ), (`test`.`t2`.`a` in on distinct_key where `test`.`t2`.`a` = ``.`a`)))) +# Specifying combinations of SUBQUERY and SEMIJOIN/NO_SEMIJOIN +# for same query block gives warning +# First has effect, second is ignored +EXPLAIN EXTENDED +SELECT * FROM t2 +WHERE t2.a IN (SELECT /*+ SUBQUERY(INTOEXISTS) SEMIJOIN() */ a FROM t1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index +2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Warning 4206 Hint SEMIJOIN() is ignored as conflicting/duplicated +Note 1003 /* select#1 */ select /*+ SUBQUERY(@`select#2` INTOEXISTS) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,(((`test`.`t2`.`a`) in t1 on PRIMARY)))) +# Try opposite order +EXPLAIN EXTENDED +SELECT * FROM t2 +WHERE t2.a IN (SELECT /*+ NO_SEMIJOIN() SUBQUERY(MATERIALIZATION) */ a FROM t1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index +2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Warning 4206 Hint SUBQUERY(MATERIALIZATION) is ignored as conflicting/duplicated +Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`select#2`) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,(((`test`.`t2`.`a`) in t1 on PRIMARY)))) +# Specify at different levels, hint inside block has effect +EXPLAIN EXTENDED +SELECT /*+ SUBQUERY(@subq MATERIALIZATION) */ * FROM t2 +WHERE t2.a IN (SELECT /*+ QB_NAME(subq) SEMIJOIN() */ a FROM t1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 index PRIMARY PRIMARY 4 NULL 4 100.00 Using index +1 PRIMARY t2 ref a a 4 test.t1.a 1 100.00 Using index +Warnings: +Warning 4206 Hint SUBQUERY(@`subq` MATERIALIZATION) is ignored as conflicting/duplicated +Note 1003 select /*+ SEMIJOIN(@`subq`) */ `test`.`t2`.`a` AS `a` from `test`.`t1` join `test`.`t2` where `test`.`t2`.`a` = `test`.`t1`.`a` +EXPLAIN EXTENDED +SELECT /*+ SUBQUERY(@subq INTOEXISTS) */ * FROM t2 +WHERE t2.a IN (SELECT /*+ QB_NAME(subq) NO_SEMIJOIN() */ a FROM t1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index +2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Warning 4206 Hint SUBQUERY(@`subq` INTOEXISTS) is ignored as conflicting/duplicated +Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq`) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,(((`test`.`t2`.`a`) in t1 on PRIMARY)))) +EXPLAIN EXTENDED +SELECT /*+ SEMIJOIN(@subq FIRSTMATCH) */ * FROM t2 +WHERE t2.a IN (SELECT /*+ QB_NAME(subq) SUBQUERY(@subq INTOEXISTS) */ a FROM t1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index +2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Warning 4206 Hint SEMIJOIN(@`subq` FIRSTMATCH) is ignored as conflicting/duplicated +Note 1003 /* select#1 */ select /*+ SUBQUERY(@`subq` INTOEXISTS) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <`test`.`t2`.`a`>((`test`.`t2`.`a`,(((`test`.`t2`.`a`) in t1 on PRIMARY)))) +DROP TABLE t1,t2,t3; diff --git a/mysql-test/main/opt_hints_subquery.test b/mysql-test/main/opt_hints_subquery.test new file mode 100644 index 00000000000..9a7d18ddb8a --- /dev/null +++ b/mysql-test/main/opt_hints_subquery.test @@ -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 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 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 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 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; + diff --git a/mysql-test/suite/sys_vars/r/optimizer_switch_basic.result b/mysql-test/suite/sys_vars/r/optimizer_switch_basic.result index 7d735f95b50..05aed97b6e8 100644 --- a/mysql-test/suite/sys_vars/r/optimizer_switch_basic.result +++ b/mysql-test/suite/sys_vars/r/optimizer_switch_basic.result @@ -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; diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result index 2678a1aacd5..cee7576a7bb 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result @@ -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 diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result index 9e4cfa7f07c..d91f5df6798 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result @@ -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 diff --git a/mysql-test/suite/sys_vars/t/optimizer_switch_basic.test b/mysql-test/suite/sys_vars/t/optimizer_switch_basic.test index a5162075e35..ada22845f3e 100644 --- a/mysql-test/suite/sys_vars/t/optimizer_switch_basic.test +++ b/mysql-test/suite/sys_vars/t/optimizer_switch_basic.test @@ -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"; diff --git a/mysql-test/suite/sysschema/r/optimizer_switch.result b/mysql-test/suite/sysschema/r/optimizer_switch.result index ceabebf0f2e..29a8e11c48b 100644 --- a/mysql-test/suite/sysschema/r/optimizer_switch.result +++ b/mysql-test/suite/sysschema/r/optimizer_switch.result @@ -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 diff --git a/sql/opt_hints.cc b/sql/opt_hints.cc index e1ce5c13842..0f65802ad00 100644 --- a/sql/opt_hints.cc +++ b/sql/opt_hints.cc @@ -40,6 +40,8 @@ struct st_opt_hint_info opt_hint_info[]= {{STRING_WITH_LEN("NO_RANGE_OPTIMIZATION")}, true, false}, {{STRING_WITH_LEN("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(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; @@ -650,7 +711,7 @@ bool Parser::Index_level_hint::resolve(Parse_context *pc) const DBUG_ASSERT(0); return true; } - + const Hint_param_table_ext &table_ext= *this; const Lex_ident_sys qb_name_sys= table_ext.Query_block_name:: to_ident_sys(pc->thd); @@ -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; } diff --git a/sql/opt_hints.h b/sql/opt_hints.h index fec5fc25c2f..b7eae34581b 100644 --- a/sql/opt_hints.h +++ b/sql/opt_hints.h @@ -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 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 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. diff --git a/sql/opt_hints_parser.cc b/sql/opt_hints_parser.cc index 8e8c18eba53..b7a4881301c 100644 --- a/sql/opt_hints_parser.cc +++ b/sql/opt_hints_parser.cc @@ -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); +} diff --git a/sql/opt_hints_parser.h b/sql/opt_hints_parser.h index d37779966d5..9c409255895 100644 --- a/sql/opt_hints_parser.h +++ b/sql/opt_hints_parser.h @@ -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 + { + public: + using TOKEN::TOKEN; + }; + class Identifier: public TOKEN { 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 + { + 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 + { + public: + using TokenChoice::TokenChoice; + }; + + + /* + strategy_list ::= strategy_name [ {, strategy_name }... ] + opt_strategy_list ::= [ strategy_list ] + */ + class Semijoin_strategy_list_container: public List + { + 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 + { + public: + using LIST::LIST; + }; + + + class Hint_param_opt_sj_strategy_list: public LIST + { + 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 + { + public: + using OR2::OR2; + }; + +public: + /* + semijoin_hint ::= semijoin_hint_type ( semijoin_hint_body ) + */ + class Semijoin_hint: public AND4 + { + 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 + { + public: + using TokenChoice::TokenChoice; + }; + + class Hint_param_subquery_strategy: public TokenChoice + { + 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 + { + public: + using OR2::OR2; + }; + + +public: + // subquery_hint ::= SUBQUERY( subquery_hint_body ) + class Subquery_hint: public AND4 + { + 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 + 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 { @@ -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 diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 81ffe95480c..d473a271787 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -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 diff --git a/sql/opt_subselect.h b/sql/opt_subselect.h index 8b4dd1f0092..4ec30d47f75 100644 --- a/sql/opt_subselect.h +++ b/sql/opt_subselect.h @@ -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, diff --git a/sql/simple_parser.h b/sql/simple_parser.h index f51b535059e..69110130105 100644 --- a/sql/simple_parser.h +++ b/sql/simple_parser.h @@ -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 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 OR6: public A, public B, public C, public D, public E, public F + { + public: + OR6() + { } + OR6(OR6 &&rhs) + :A(std::move(static_cast(rhs))), + B(std::move(static_cast(rhs))), + C(std::move(static_cast(rhs))), + D(std::move(static_cast(rhs))), + E(std::move(static_cast(rhs))), + F(std::move(static_cast(rhs))) + { } + OR6 & operator=(OR6 &&rhs) + { + A::operator=(std::move(static_cast(rhs))); + B::operator=(std::move(static_cast(rhs))); + C::operator=(std::move(static_cast(rhs))); + D::operator=(std::move(static_cast(rhs))); + E::operator=(std::move(static_cast(rhs))); + F::operator=(std::move(static_cast(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 diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 6c58a14128f..f2c0099085e 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -8320,6 +8320,7 @@ bool setup_tables(THD *thd, Name_resolution_context *context, my_error(ER_TOO_MANY_TABLES, MYF(0), static_cast(MAX_TABLES)); DBUG_RETURN(1); } + if (qb_hints && // QB hints initialized !table_list->opt_hints_table) // Table hints are not adjusted yet { diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 75bdf92c376..79f649e75a9 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -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 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(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. diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 50bd1874ddd..df613c415ba 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -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; diff --git a/sql/sql_list.h b/sql/sql_list.h index 03f855723c8..b6191b51ca3 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -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(node->info); } - const T *operator->() { return static_cast(node->info); } - - bool operator==(const typename List::const_iterator &rhs) - { - return node == rhs.node; - } - - bool operator!=(const typename List::const_iterator &rhs) - { - return node != rhs.node; - } - - private: - const list_node* node{&end_of_list}; - }; }; diff --git a/sql/sql_priv.h b/sql/sql_priv.h index 42b95bccd1d..9791fbe2fc8 100644 --- a/sql/sql_priv.h +++ b/sql/sql_priv.h @@ -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 | \ diff --git a/sql/sql_select.cc b/sql/sql_select.cc index d2fa54a429c..65ce83f1b75 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -5601,6 +5601,7 @@ make_join_statistics(JOIN *join, 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 &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); diff --git a/sql/sql_select.h b/sql/sql_select.h index 25d8cdaafed..0a9fb36727d 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -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); }; diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 0f6924a212c..29d20ec17e8 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -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", diff --git a/sql/table.h b/sql/table.h index 80fe8c7d208..d6f32f9feb8 100644 --- a/sql/table.h +++ b/sql/table.h @@ -3447,6 +3447,10 @@ typedef struct st_nested_join table_map sj_corr_tables; table_map direct_children_map; List 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.