Current Path : /home/usr.opt/mysql57/mysql-test/r/ |
FreeBSD hs32.drive.ne.jp 9.1-RELEASE FreeBSD 9.1-RELEASE #1: Wed Jan 14 12:18:08 JST 2015 root@hs32.drive.ne.jp:/sys/amd64/compile/hs32 amd64 |
Current File : /home/usr.opt/mysql57/mysql-test/r/opt_hints_subquery.result |
# WL#8244 Hints for subquery execution 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 OK test.t2 analyze status OK test.t3 analyze status OK This query will normally use Table Pull-out EXPLAIN SELECT * FROM t2 WHERE t2.a IN (SELECT a FROM t1); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using index 1 SIMPLE t1 NULL eq_ref PRIMARY PRIMARY 4 test.t2.a 1 100.00 Using index Warnings: Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a` from `test`.`t1` join `test`.`t2` where (`test`.`t1`.`a` = `test`.`t2`.`a`) Check that we can disable SEMIJOIN transformation EXPLAIN SELECT * FROM t2 WHERE t2.a IN (SELECT /*+ NO_SEMIJOIN() */ a FROM t1); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 NULL index NULL a 4 NULL 4 100.00 Using where; Using index 2 DEPENDENT SUBQUERY t1 NULL 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 <in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on PRIMARY))) Same with hint in outer query EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq) */ a FROM t1); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 NULL index NULL a 4 NULL 4 100.00 Using where; Using index 2 DEPENDENT SUBQUERY t1 NULL 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 <in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on PRIMARY))) Query with two sub-queries EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE tx NULL index PRIMARY PRIMARY 4 NULL 4 100.00 Using index 1 SIMPLE t3 NULL ALL a NULL NULL NULL 3 33.33 Using where; Using join buffer (Block Nested Loop) 1 SIMPLE ty NULL eq_ref PRIMARY PRIMARY 4 test.t3.b 1 100.00 Using index Warnings: Note 1003 /* select#1 */ 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`.`t3`.`b`) and (`test`.`t3`.`a` = `test`.`tx`.`a`)) No SEMIJOIN transformation for first subquery EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 NULL ALL NULL NULL NULL NULL 3 100.00 Using where 1 PRIMARY ty NULL eq_ref PRIMARY PRIMARY 4 test.t3.b 1 100.00 Using index 2 DEPENDENT SUBQUERY tx NULL 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 <in_optimizer>(`test`.`t3`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t3`.`a`) in t1 on PRIMARY)))) EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 NULL ALL NULL NULL NULL NULL 3 100.00 Using where 1 PRIMARY ty NULL eq_ref PRIMARY PRIMARY 4 test.t3.b 1 100.00 Using index 2 DEPENDENT SUBQUERY tx NULL 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 <in_optimizer>(`test`.`t3`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t3`.`a`) in t1 on PRIMARY)))) No SEMIJOIN transformation for latter subquery EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 NULL ALL a NULL NULL NULL 3 100.00 Using where 1 PRIMARY tx NULL eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 Using index 3 DEPENDENT SUBQUERY ty NULL 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 <in_optimizer>(`test`.`t3`.`b`,<exists>(<primary_index_lookup>(<cache>(`test`.`t3`.`b`) in t1 on PRIMARY)))) EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 NULL ALL a NULL NULL NULL 3 100.00 Using where 1 PRIMARY tx NULL eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 Using index 3 DEPENDENT SUBQUERY ty NULL 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 <in_optimizer>(`test`.`t3`.`b`,<exists>(<primary_index_lookup>(<cache>(`test`.`t3`.`b`) in t1 on PRIMARY)))) No SEMIJOIN transformation for any subquery EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 NULL ALL NULL NULL NULL NULL 3 100.00 Using where 3 DEPENDENT SUBQUERY ty NULL unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index 2 DEPENDENT SUBQUERY tx NULL 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 (<in_optimizer>(`test`.`t3`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t3`.`a`) in t1 on PRIMARY))) and <in_optimizer>(`test`.`t3`.`b`,<exists>(<primary_index_lookup>(<cache>(`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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 NULL ALL NULL NULL NULL NULL 3 100.00 Using where 3 DEPENDENT SUBQUERY ty NULL unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index 2 DEPENDENT SUBQUERY tx NULL unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq1`) NO_SEMIJOIN(@`subq2`) */ `test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t3` where (<in_optimizer>(`test`.`t3`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t3`.`a`) in t1 on PRIMARY))) and <in_optimizer>(`test`.`t3`.`b`,<exists>(<primary_index_lookup>(<cache>(`test`.`t3`.`b`) in t1 on PRIMARY)))) Query with nested sub-queries EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL ALL a NULL NULL NULL 3 100.00 NULL 1 SIMPLE tx NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; Using join buffer (Block Nested Loop) 1 SIMPLE ty NULL eq_ref PRIMARY PRIMARY 4 test.tx.b 1 100.00 Using index Warnings: Note 1003 /* select#1 */ 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`.`tx`.`b`)) No SEMIJOIN transformation for outer subquery EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 NULL ALL NULL NULL NULL NULL 3 100.00 Using where 2 DEPENDENT SUBQUERY tx NULL eq_ref PRIMARY PRIMARY 4 func 1 100.00 Using where 2 DEPENDENT SUBQUERY ty NULL 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 <in_optimizer>(`test`.`t3`.`a`,<exists>(/* select#2 */ select /*+ QB_NAME(`subq1`) */ 1 from `test`.`t1` `ty` join `test`.`t1` `tx` where ((`test`.`ty`.`a` = `test`.`tx`.`b`) and (<cache>(`test`.`t3`.`a`) = `test`.`tx`.`a`)))) No SEMIJOIN transformation for inner-most subquery EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 NULL ALL a NULL NULL NULL 3 100.00 NULL 1 PRIMARY tx NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; Using join buffer (Block Nested Loop) 3 SUBQUERY ty NULL index PRIMARY PRIMARY 4 NULL 4 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 <in_optimizer>(`test`.`tx`.`b`,`test`.`tx`.`b` in ( <materialize> (/* select#3 */ select /*+ QB_NAME(`subq2`) */ `test`.`ty`.`a` from `test`.`t1` `ty` where 1 ), <primary_index_lookup>(`test`.`tx`.`b` in <temporary table> on <auto_key> where ((`test`.`tx`.`b` = `materialized-subquery`.`a`)))))) No SEMIJOIN transformation at all EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 NULL ALL NULL NULL NULL NULL 3 100.00 Using where 2 DEPENDENT SUBQUERY tx NULL unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using where 3 DEPENDENT SUBQUERY ty NULL 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 <in_optimizer>(`test`.`t3`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t3`.`a`) in t1 on PRIMARY where (<in_optimizer>(`test`.`tx`.`b`,<exists>(<primary_index_lookup>(<cache>(`test`.`tx`.`b`) in t1 on PRIMARY))) and (<cache>(`test`.`t3`.`a`) = `test`.`tx`.`a`))))) This query does not support SEMIJOIN. SEMIJOIN hint is ignored EXPLAIN SELECT /*+ SEMIJOIN(@subq) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq) */ min(a) FROM t1 group by a); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 NULL index NULL a 4 NULL 4 100.00 Using where; Using index 2 SUBQUERY t1 NULL index PRIMARY PRIMARY 4 NULL 4 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`subq`) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,`test`.`t2`.`a` in ( <materialize> (/* select#2 */ select /*+ QB_NAME(`subq`) */ min(`test`.`t1`.`a`) from `test`.`t1` group by `test`.`t1`.`a` having 1 ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on <auto_key> where ((`test`.`t2`.`a` = `materialized-subquery`.`min(a)`))))) This query will get LooseScan by default EXPLAIN SELECT * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; LooseScan 1 SIMPLE t2 NULL ref a a 4 test.t3.a 1 100.00 Using index Warnings: Note 1003 /* select#1 */ 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 SELECT /*+ NO_SEMIJOIN(@subq1 LOOSESCAN) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using index 1 SIMPLE t3 NULL ref a a 4 test.t2.a 1 100.00 Using index; FirstMatch(t2) Warnings: Note 1003 /* select#1 */ 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, MatLookup is then used EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq1 FIRSTMATCH, LOOSESCAN) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using where; Using index 1 SIMPLE <subquery2> NULL eq_ref <auto_key> <auto_key> 4 test.t2.a 1 100.00 NULL 2 MATERIALIZED t3 NULL index a a 4 NULL 3 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq1` FIRSTMATCH, LOOSESCAN) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where (`<subquery2>`.`a` = `test`.`t2`.`a`) Let's also turn off Materialization, DuplicateWeedout should then be used EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq1 FIRSTMATCH, LOOSESCAN, MATERIALIZATION) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; Start temporary 1 SIMPLE t2 NULL ref a a 4 test.t3.a 1 100.00 Using index; End temporary Warnings: Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq1` FIRSTMATCH, LOOSESCAN, MATERIALIZATION) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where (`test`.`t2`.`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 t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; Start temporary 1 SIMPLE t2 NULL ref a a 4 test.t3.a 1 100.00 Using index; End temporary Warnings: Note 1003 /* select#1 */ 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 SELECT /*+ NO_SEMIJOIN(@subq1 FIRSTMATCH, MATERIALIZATION, DUPSWEEDOUT) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; LooseScan 1 SIMPLE t2 NULL ref a a 4 test.t3.a 1 100.00 Using index Warnings: Note 1003 /* select#1 */ 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 SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; LooseScan 1 SIMPLE t2 NULL ref a a 4 test.t3.a 1 100.00 Using index Warnings: Note 1003 /* select#1 */ 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 SELECT /*+ SEMIJOIN(@subq1 FIRSTMATCH) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using index 1 SIMPLE t3 NULL ref a a 4 test.t2.a 1 100.00 Using index; FirstMatch(t2) Warnings: Note 1003 /* select#1 */ 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 SELECT /*+ SEMIJOIN(@subq1 MATERIALIZATION) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using where; Using index 1 SIMPLE <subquery2> NULL eq_ref <auto_key> <auto_key> 4 test.t2.a 1 100.00 NULL 2 MATERIALIZED t3 NULL index a a 4 NULL 3 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`subq1` MATERIALIZATION) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where (`<subquery2>`.`a` = `test`.`t2`.`a`) Force DuplicateWeedout EXPLAIN SELECT /*+ SEMIJOIN(@subq1 DUPSWEEDOUT) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; Start temporary 1 SIMPLE t2 NULL ref a a 4 test.t3.a 1 100.00 Using index; End temporary Warnings: Note 1003 /* select#1 */ 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 SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN, DUPSWEEDOUT) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; LooseScan 1 SIMPLE t2 NULL ref a a 4 test.t3.a 1 100.00 Using index Warnings: Note 1003 /* select#1 */ 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 SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN, MATERIALIZATION, DUPSWEEDOUT) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; LooseScan 1 SIMPLE t2 NULL ref a a 4 test.t3.a 1 100.00 Using index Warnings: Note 1003 /* select#1 */ 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 SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN, FIRSTMATCH, MATERIALIZATION, DUPSWEEDOUT) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; LooseScan 1 SIMPLE t2 NULL ref a a 4 test.t3.a 1 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ 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`) Drop LooseScan from list of strategies, FirstMatch will be used EXPLAIN SELECT /*+ SEMIJOIN(@subq1 FIRSTMATCH, MATERIALIZATION, DUPSWEEDOUT) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using index 1 SIMPLE t3 NULL ref a a 4 test.t2.a 1 100.00 Using index; FirstMatch(t2) Warnings: Note 1003 /* select#1 */ 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 FirstMatch, MatLookup is next EXPLAIN SELECT /*+ SEMIJOIN(@subq1 MATERIALIZATION, DUPSWEEDOUT) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using where; Using index 1 SIMPLE <subquery2> NULL eq_ref <auto_key> <auto_key> 4 test.t2.a 1 100.00 NULL 2 MATERIALIZED t3 NULL index a a 4 NULL 3 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`subq1` MATERIALIZATION, DUPSWEEDOUT) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where (`<subquery2>`.`a` = `test`.`t2`.`a`) For this query LooseScan and Materialization is not applicable EXPLAIN SELECT * FROM t1 WHERE t1.b IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3 WHERE t3.b = t1.a); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 100.00 NULL 1 SIMPLE t3 NULL ALL a NULL NULL NULL 3 33.33 Using where; FirstMatch(t1); Using join buffer (Block Nested Loop) Warnings: Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1 Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) where ((`test`.`t3`.`a` = `test`.`t1`.`b`) and (`test`.`t3`.`b` = `test`.`t1`.`a`)) Turn off all applicable strategies. DuplicateWeedout should be used EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL ALL a NULL NULL NULL 3 100.00 Start temporary 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; End temporary; Using join buffer (Block Nested Loop) Warnings: Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1 Note 1003 /* select#1 */ 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`.`b` = `test`.`t3`.`a`) and (`test`.`t1`.`a` = `test`.`t3`.`b`)) Similar with SEMIJOIN hint EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL ALL a NULL NULL NULL 3 100.00 Start temporary 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; End temporary; Using join buffer (Block Nested Loop) Warnings: Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1 Note 1003 /* select#1 */ 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`.`b` = `test`.`t3`.`a`) and (`test`.`t1`.`a` = `test`.`t3`.`b`)) Test multiple subqueries. Default for this query is Loosecan for first and FirstMatch for latter EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; LooseScan 1 SIMPLE t1 NULL eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 Using where 1 SIMPLE t2 NULL ref a a 4 test.t1.b 1 100.00 Using index; FirstMatch(t1) Warnings: Note 1003 /* select#1 */ select `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`) and (`test`.`t1`.`a` = `test`.`t3`.`a`)) Forcing the default strategy should not change anything EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; LooseScan 1 SIMPLE t1 NULL eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 Using where 1 SIMPLE t2 NULL ref a a 4 test.t1.b 1 100.00 Using index; FirstMatch(t1) Warnings: Note 1003 /* select#1 */ 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`.`t2`.`a` = `test`.`t1`.`b`) and (`test`.`t1`.`a` = `test`.`t3`.`a`)) Forcing a strategy for one, may change the other due to cost changes EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using index; LooseScan 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; Using join buffer (Block Nested Loop) 1 SIMPLE t3 NULL ref a a 4 test.t1.a 1 100.00 Using index; FirstMatch(t1) Warnings: Note 1003 /* select#1 */ 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`.`t1`.`b` = `test`.`t2`.`a`) and (`test`.`t3`.`a` = `test`.`t1`.`a`)) Forcing same strategy for both EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 100.00 Using where 1 SIMPLE t3 NULL ref a a 4 test.t1.a 1 100.00 Using index; FirstMatch(t1) 1 SIMPLE t2 NULL ref a a 4 test.t1.b 1 100.00 Using index; FirstMatch(t3) Warnings: Note 1003 /* select#1 */ 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`.`t2`.`a` = `test`.`t1`.`b`) and (`test`.`t3`.`a` = `test`.`t1`.`a`)) Loosescan for both is not possible, ends up with DuplicateWeedout EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; Start temporary 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; Using join buffer (Block Nested Loop) 1 SIMPLE t2 NULL ref a a 4 test.t1.b 1 100.00 Using index; End temporary Warnings: Note 1003 /* select#1 */ 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`.`t2`.`a` = `test`.`t1`.`b`) and (`test`.`t1`.`a` = `test`.`t3`.`a`)) Swap strategies compared to default EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using index; LooseScan 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; Using join buffer (Block Nested Loop) 1 SIMPLE t3 NULL ref a a 4 test.t1.a 1 100.00 Using index; FirstMatch(t1) Warnings: Note 1003 /* select#1 */ 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`.`t1`.`b` = `test`.`t2`.`a`) and (`test`.`t3`.`a` = `test`.`t1`.`a`)) Different subsets of strategies for different subqueries EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; LooseScan 1 SIMPLE t1 NULL eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 Using where 1 SIMPLE <subquery3> NULL eq_ref <auto_key> <auto_key> 4 test.t1.b 1 100.00 NULL 3 MATERIALIZED t2 NULL index a a 4 NULL 4 100.00 Using index Warnings: Note 1003 /* select#1 */ 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 ((`<subquery3>`.`a` = `test`.`t1`.`b`) and (`test`.`t1`.`a` = `test`.`t3`.`a`)) Vice versa EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; Start temporary 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; End temporary; Using join buffer (Block Nested Loop) 1 SIMPLE t2 NULL ref a a 4 test.t1.b 1 100.00 Using index; FirstMatch(t1) Warnings: Note 1003 /* select#1 */ 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`.`t2`.`a` = `test`.`t1`.`b`) and (`test`.`t1`.`a` = `test`.`t3`.`a`)) Another combination EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using index; LooseScan 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; Using join buffer (Block Nested Loop) 1 SIMPLE t3 NULL ref a a 4 test.t1.a 1 100.00 Using index; FirstMatch(t1) Warnings: Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`subq1` FIRSTMATCH, MATERIALIZATION) 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`.`t1`.`b` = `test`.`t2`.`a`) and (`test`.`t3`.`a` = `test`.`t1`.`a`)) Turn off default EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using index; LooseScan 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; Using join buffer (Block Nested Loop) 1 SIMPLE t3 NULL ref a a 4 test.t1.a 1 100.00 Using index; FirstMatch(t1) Warnings: Note 1003 /* select#1 */ 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`.`t1`.`b` = `test`.`t2`.`a`) and (`test`.`t3`.`a` = `test`.`t1`.`a`)) Also turn off 2nd choice. Gives DuplicateWeedout over both EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; Start temporary 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; Using join buffer (Block Nested Loop) 1 SIMPLE t2 NULL ref a a 4 test.t1.b 1 100.00 Using index; End temporary Warnings: Note 1003 /* select#1 */ 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`.`t2`.`a` = `test`.`t1`.`b`) and (`test`.`t1`.`a` = `test`.`t3`.`a`)) Also turn off DuplicateWeedout. Materialization is only one left. EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 100.00 Using where 1 SIMPLE <subquery2> NULL eq_ref <auto_key> <auto_key> 4 test.t1.a 1 100.00 NULL 1 SIMPLE <subquery3> NULL eq_ref <auto_key> <auto_key> 4 test.t1.b 1 100.00 NULL 2 MATERIALIZED t3 NULL index a a 4 NULL 3 100.00 Using index 3 MATERIALIZED t2 NULL index a a 4 NULL 4 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq1` FIRSTMATCH, LOOSESCAN, 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 ((`<subquery3>`.`a` = `test`.`t1`.`b`) and (`<subquery2>`.`a` = `test`.`t1`.`a`)) Force materialization with SEMIJOIN hints instead EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 100.00 Using where 1 SIMPLE <subquery2> NULL eq_ref <auto_key> <auto_key> 4 test.t1.a 1 100.00 NULL 1 SIMPLE <subquery3> NULL eq_ref <auto_key> <auto_key> 4 test.t1.b 1 100.00 NULL 2 MATERIALIZED t3 NULL index a a 4 NULL 3 100.00 Using index 3 MATERIALIZED t2 NULL index a a 4 NULL 4 100.00 Using index Warnings: Note 1003 /* select#1 */ 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 ((`<subquery3>`.`a` = `test`.`t1`.`b`) and (`<subquery2>`.`a` = `test`.`t1`.`a`)) This query gives DuplicateWeedout over both since combining DuplicateWeedout with another strategy does not seem possible. EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; Start temporary 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; Using join buffer (Block Nested Loop) 1 SIMPLE t2 NULL ref a a 4 test.t1.b 1 100.00 Using index; End temporary Warnings: Note 1003 /* select#1 */ 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`) and (`test`.`t1`.`a` = `test`.`t3`.`a`)) More alternatives for 2nd subquery gives Materialization for first EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE <subquery2> NULL ALL NULL NULL NULL NULL NULL 100.00 NULL 1 SIMPLE t1 NULL eq_ref PRIMARY PRIMARY 4 <subquery2>.a 1 100.00 Using where 1 SIMPLE t2 NULL ref a a 4 test.t1.b 1 100.00 Using index; FirstMatch(t1) 2 MATERIALIZED t3 NULL index a a 4 NULL 3 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`subq1` MATERIALIZATION) 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 ((`test`.`t2`.`a` = `test`.`t1`.`b`) and (`test`.`t1`.`a` = `<subquery2>`.`a`)) A query with nested subqueries which by default is materialized together EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE <subquery2> NULL ALL NULL NULL NULL NULL NULL 100.00 NULL 1 SIMPLE t1 NULL eq_ref PRIMARY PRIMARY 4 <subquery2>.a 1 100.00 NULL 2 MATERIALIZED t3 NULL ALL a NULL NULL NULL 3 100.00 Using where 2 MATERIALIZED t2 NULL ref a a 4 test.t3.b 1 100.00 Using index Warnings: Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t2` join `test`.`t3`) where ((`test`.`t1`.`a` = `<subquery2>`.`a`) and (`test`.`t2`.`a` = `test`.`t3`.`b`)) Let's turn off Materialization, DuplicateWeedout is then SELECTed EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq1 MATERIALIZATION) */ * 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using index; Start temporary 1 SIMPLE t3 NULL ALL a NULL NULL NULL 3 33.33 Using where; Using join buffer (Block Nested Loop) 1 SIMPLE t1 NULL eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 End temporary Warnings: Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq1` MATERIALIZATION) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t2` join `test`.`t3`) where ((`test`.`t1`.`a` = `test`.`t3`.`a`) and (`test`.`t3`.`b` = `test`.`t2`.`a`)) Let's also turn off DuplicateWeedout, FirstMatch is then used EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq1 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 100.00 NULL 1 SIMPLE t3 NULL ref a a 4 test.t1.a 1 100.00 Using where 1 SIMPLE t2 NULL ref a a 4 test.t3.b 1 100.00 Using index; FirstMatch(t1) Warnings: Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq1` MATERIALIZATION, DUPSWEEDOUT) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t2` join `test`.`t3`) where ((`test`.`t3`.`a` = `test`.`t1`.`a`) and (`test`.`t2`.`a` = `test`.`t3`.`b`)) Also turn off FirstMatch. LooseScan not usable. Back to DuplicateWeedout EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq1 MATERIALIZATION, DUPSWEEDOUT, 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using index; Start temporary 1 SIMPLE t3 NULL ALL a NULL NULL NULL 3 33.33 Using where; Using join buffer (Block Nested Loop) 1 SIMPLE t1 NULL eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 End temporary Warnings: Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq1` FIRSTMATCH, MATERIALIZATION, DUPSWEEDOUT) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t2` join `test`.`t3`) where ((`test`.`t1`.`a` = `test`.`t3`.`a`) and (`test`.`t3`.`b` = `test`.`t2`.`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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using index; Start temporary 1 SIMPLE t3 NULL ALL a NULL NULL NULL 3 33.33 Using where; Using join buffer (Block Nested Loop) 1 SIMPLE t1 NULL eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 End temporary Warnings: Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq1` FIRSTMATCH, LOOSESCAN, MATERIALIZATION, DUPSWEEDOUT) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t2` join `test`.`t3`) where ((`test`.`t1`.`a` = `test`.`t3`.`a`) and (`test`.`t3`.`b` = `test`.`t2`.`a`)) Test same query with SEMIJOIN hint Force Materialization, should not change anything EXPLAIN SELECT /*+ SEMIJOIN(@subq1 MATERIALIZATION) */ * 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE <subquery2> NULL ALL NULL NULL NULL NULL NULL 100.00 NULL 1 SIMPLE t1 NULL eq_ref PRIMARY PRIMARY 4 <subquery2>.a 1 100.00 NULL 2 MATERIALIZED t3 NULL ALL a NULL NULL NULL 3 100.00 Using where 2 MATERIALIZED t2 NULL ref a a 4 test.t3.b 1 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`subq1` MATERIALIZATION) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t2` join `test`.`t3`) where ((`test`.`t1`.`a` = `<subquery2>`.`a`) and (`test`.`t2`.`a` = `test`.`t3`.`b`)) Force LooseScan, will use DuplicateWeedout EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using index; Start temporary 1 SIMPLE t3 NULL ALL a NULL NULL NULL 3 33.33 Using where; Using join buffer (Block Nested Loop) 1 SIMPLE t1 NULL eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 End temporary Warnings: Note 1003 /* select#1 */ 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`.`t1`.`a` = `test`.`t3`.`a`) and (`test`.`t3`.`b` = `test`.`t2`.`a`)) Force FirstMatch EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 100.00 NULL 1 SIMPLE t3 NULL ref a a 4 test.t1.a 1 100.00 Using where 1 SIMPLE t2 NULL ref a a 4 test.t3.b 1 100.00 Using index; FirstMatch(t1) Warnings: Note 1003 /* select#1 */ 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`.`t3`.`a` = `test`.`t1`.`a`) and (`test`.`t2`.`a` = `test`.`t3`.`b`)) Force DuplicateWeedout EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using index; Start temporary 1 SIMPLE t3 NULL ALL a NULL NULL NULL 3 33.33 Using where; Using join buffer (Block Nested Loop) 1 SIMPLE t1 NULL eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 End temporary Warnings: Note 1003 /* select#1 */ 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`.`t1`.`a` = `test`.`t3`.`a`) and (`test`.`t3`.`b` = `test`.`t2`.`a`)) If Materialization is among candidates, it will be used EXPLAIN SELECT /*+ SEMIJOIN(@subq1 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE <subquery2> NULL ALL NULL NULL NULL NULL NULL 100.00 NULL 1 SIMPLE t1 NULL eq_ref PRIMARY PRIMARY 4 <subquery2>.a 1 100.00 NULL 2 MATERIALIZED t3 NULL ALL a NULL NULL NULL 3 100.00 Using where 2 MATERIALIZED t2 NULL ref a a 4 test.t3.b 1 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`subq1` MATERIALIZATION, DUPSWEEDOUT) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t2` join `test`.`t3`) where ((`test`.`t1`.`a` = `<subquery2>`.`a`) and (`test`.`t2`.`a` = `test`.`t3`.`b`)) EXPLAIN SELECT /*+ SEMIJOIN(@subq1 MATERIALIZATION, 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE <subquery2> NULL ALL NULL NULL NULL NULL NULL 100.00 NULL 1 SIMPLE t1 NULL eq_ref PRIMARY PRIMARY 4 <subquery2>.a 1 100.00 NULL 2 MATERIALIZED t3 NULL ALL a NULL NULL NULL 3 100.00 Using where 2 MATERIALIZED t2 NULL ref a a 4 test.t3.b 1 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`subq1` LOOSESCAN, MATERIALIZATION, DUPSWEEDOUT) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t2` join `test`.`t3`) where ((`test`.`t1`.`a` = `<subquery2>`.`a`) and (`test`.`t2`.`a` = `test`.`t3`.`b`)) EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE <subquery2> NULL ALL NULL NULL NULL NULL NULL 100.00 NULL 1 SIMPLE t1 NULL eq_ref PRIMARY PRIMARY 4 <subquery2>.a 1 100.00 NULL 2 MATERIALIZED t3 NULL ALL a NULL NULL NULL 3 100.00 Using where 2 MATERIALIZED t2 NULL ref a a 4 test.t3.b 1 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`subq1` FIRSTMATCH, LOOSESCAN, MATERIALIZATION, DUPSWEEDOUT) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t2` join `test`.`t3`) where ((`test`.`t1`.`a` = `<subquery2>`.`a`) and (`test`.`t2`.`a` = `test`.`t3`.`b`)) Drop Materialization. DuplicateWeedout will be used EXPLAIN SELECT /*+ SEMIJOIN(@subq1 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using index; Start temporary 1 SIMPLE t3 NULL ALL a NULL NULL NULL 3 33.33 Using where; Using join buffer (Block Nested Loop) 1 SIMPLE t1 NULL eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 End temporary Warnings: Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`subq1` 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`.`t1`.`a` = `test`.`t3`.`a`) and (`test`.`t3`.`b` = `test`.`t2`.`a`)) Drop DuplicateWeedout, FirstMatch is next EXPLAIN SELECT /*+ SEMIJOIN(@subq1 FIRSTMATCH, 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 100.00 NULL 1 SIMPLE t3 NULL ref a a 4 test.t1.a 1 100.00 Using where 1 SIMPLE t2 NULL ref a a 4 test.t3.b 1 100.00 Using index; FirstMatch(t1) Warnings: Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`subq1` FIRSTMATCH, LOOSESCAN) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t2` join `test`.`t3`) where ((`test`.`t3`.`a` = `test`.`t1`.`a`) and (`test`.`t2`.`a` = `test`.`t3`.`b`)) Strategy hints on inner-most query is ignored since sj-nests are merged EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq2 MATERIALIZATION) */ * 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE <subquery2> NULL ALL NULL NULL NULL NULL NULL 100.00 NULL 1 SIMPLE t1 NULL eq_ref PRIMARY PRIMARY 4 <subquery2>.a 1 100.00 NULL 2 MATERIALIZED t3 NULL ALL a NULL NULL NULL 3 100.00 Using where 2 MATERIALIZED t2 NULL ref a a 4 test.t3.b 1 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq2` MATERIALIZATION) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t2` join `test`.`t3`) where ((`test`.`t1`.`a` = `<subquery2>`.`a`) and (`test`.`t2`.`a` = `test`.`t3`.`b`)) Ditto EXPLAIN SELECT /*+ SEMIJOIN(@subq2 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE <subquery2> NULL ALL NULL NULL NULL NULL NULL 100.00 NULL 1 SIMPLE t1 NULL eq_ref PRIMARY PRIMARY 4 <subquery2>.a 1 100.00 NULL 2 MATERIALIZED t3 NULL ALL a NULL NULL NULL 3 100.00 Using where 2 MATERIALIZED t2 NULL ref a a 4 test.t3.b 1 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`subq2` FIRSTMATCH) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t2` join `test`.`t3`) where ((`test`.`t1`.`a` = `<subquery2>`.`a`) and (`test`.`t2`.`a` = `test`.`t3`.`b`)) Turn off semijoin for outer subquery. FirstMatch is used for inner EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq1) */ * 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 4 100.00 Using where 2 SUBQUERY t3 NULL ALL a NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 NULL ref a a 4 test.t3.b 1 100.00 Using index; FirstMatch(t3) Warnings: Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq1`) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where <in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (/* select#2 */ select /*+ QB_NAME(`subq1`) */ `test`.`t3`.`a` from `test`.`t3` semi join (`test`.`t2`) where (`test`.`t2`.`a` = `test`.`t3`.`b`) ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on <auto_key> where ((`test`.`t1`.`a` = `materialized-subquery`.`a`))))) Do not use FirstMatch for inner EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq1) NO_SEMIJOIN(@subq2 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 4 100.00 Using where 2 SUBQUERY t3 NULL ALL a NULL NULL NULL 3 100.00 Using where 2 SUBQUERY <subquery3> NULL eq_ref <auto_key> <auto_key> 4 test.t3.b 1 100.00 NULL 3 MATERIALIZED t2 NULL index a a 4 NULL 4 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq2` FIRSTMATCH) NO_SEMIJOIN(@`subq1`) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where <in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (/* select#2 */ select /*+ QB_NAME(`subq1`) */ `test`.`t3`.`a` from `test`.`t3` semi join (`test`.`t2`) where (`<subquery3>`.`a` = `test`.`t3`.`b`) ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on <auto_key> where ((`test`.`t1`.`a` = `materialized-subquery`.`a`))))) Do not use FirstMatch nor Materialization for inner EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq1) NO_SEMIJOIN(@subq2 FIRSTMATCH, MATERIALIZATION) */ * 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 4 100.00 Using where 2 SUBQUERY t3 NULL ALL a NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 NULL ref a a 4 test.t3.b 1 100.00 Using index; Start temporary; End temporary Warnings: Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq2` FIRSTMATCH, MATERIALIZATION) NO_SEMIJOIN(@`subq1`) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where <in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (/* select#2 */ select /*+ QB_NAME(`subq1`) */ `test`.`t3`.`a` from `test`.`t3` semi join (`test`.`t2`) where (`test`.`t2`.`a` = `test`.`t3`.`b`) ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on <auto_key> where ((`test`.`t1`.`a` = `materialized-subquery`.`a`))))) LooseScan is last resort EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq1) NO_SEMIJOIN(@subq2 FIRSTMATCH, 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 4 100.00 Using where 2 SUBQUERY t2 NULL index a a 4 NULL 4 100.00 Using index; LooseScan 2 SUBQUERY t3 NULL ALL a NULL NULL NULL 3 33.33 Using where; Using join buffer (Block Nested Loop) Warnings: Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq2` FIRSTMATCH, MATERIALIZATION, DUPSWEEDOUT) NO_SEMIJOIN(@`subq1`) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where <in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (/* select#2 */ select /*+ QB_NAME(`subq1`) */ `test`.`t3`.`a` from `test`.`t3` semi join (`test`.`t2`) where (`test`.`t3`.`b` = `test`.`t2`.`a`) ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on <auto_key> where ((`test`.`t1`.`a` = `materialized-subquery`.`a`))))) Allow all stragies except default EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq1) SEMIJOIN(@subq2 MATERIALIZATION, DUPSWEEDOUT, 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 4 100.00 Using where 2 SUBQUERY t3 NULL ALL a NULL NULL NULL 3 100.00 Using where 2 SUBQUERY <subquery3> NULL eq_ref <auto_key> <auto_key> 4 test.t3.b 1 100.00 NULL 3 MATERIALIZED t2 NULL index a a 4 NULL 4 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`subq2` LOOSESCAN, MATERIALIZATION, DUPSWEEDOUT) NO_SEMIJOIN(@`subq1`) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where <in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (/* select#2 */ select /*+ QB_NAME(`subq1`) */ `test`.`t3`.`a` from `test`.`t3` semi join (`test`.`t2`) where (`<subquery3>`.`a` = `test`.`t3`.`b`) ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on <auto_key> where ((`test`.`t1`.`a` = `materialized-subquery`.`a`))))) Force a particular strategy EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq1) SEMIJOIN(@subq2 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 4 100.00 Using where 2 SUBQUERY t2 NULL index a a 4 NULL 4 100.00 Using index; LooseScan 2 SUBQUERY t3 NULL ALL a NULL NULL NULL 3 33.33 Using where; Using join buffer (Block Nested Loop) Warnings: Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`subq2` LOOSESCAN) NO_SEMIJOIN(@`subq1`) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where <in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (/* select#2 */ select /*+ QB_NAME(`subq1`) */ `test`.`t3`.`a` from `test`.`t3` semi join (`test`.`t2`) where (`test`.`t3`.`b` = `test`.`t2`.`a`) ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on <auto_key> where ((`test`.`t1`.`a` = `materialized-subquery`.`a`))))) Turn off semijoin for inner-most subquery. FirstMatch is used for outer EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq2) */ * 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 NULL ALL PRIMARY NULL NULL NULL 4 100.00 NULL 1 PRIMARY t3 NULL ALL a NULL NULL NULL 3 33.33 Using where; FirstMatch(t1); Using join buffer (Block Nested Loop) 3 SUBQUERY t2 NULL index a a 4 NULL 4 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq2`) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) where ((`test`.`t3`.`a` = `test`.`t1`.`a`) and <in_optimizer>(`test`.`t3`.`b`,`test`.`t3`.`b` in ( <materialize> (/* select#3 */ select /*+ QB_NAME(`subq2`) */ `test`.`t2`.`a` from `test`.`t2` where 1 ), <primary_index_lookup>(`test`.`t3`.`b` in <temporary table> on <auto_key> where ((`test`.`t3`.`b` = `materialized-subquery`.`a`)))))) Do not use FirstMatch for outer EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq1 FIRSTMATCH) NO_SEMIJOIN(@subq2) */ * 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 NULL ALL PRIMARY NULL NULL NULL 4 100.00 Using where 1 PRIMARY <subquery2> NULL eq_ref <auto_key> <auto_key> 4 test.t1.a 1 100.00 NULL 2 MATERIALIZED t3 NULL ALL a NULL NULL NULL 3 100.00 Using where 3 DEPENDENT SUBQUERY t2 NULL index_subquery a a 4 func 1 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq2`) NO_SEMIJOIN(@`subq1` FIRSTMATCH) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) where ((`<subquery2>`.`a` = `test`.`t1`.`a`) and <in_optimizer>(`test`.`t3`.`b`,<exists>(<index_lookup>(<cache>(`test`.`t3`.`b`) in t2 on a)))) Do not use FirstMatch nor Materialization for outer EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq1 FIRSTMATCH, MATERIALIZATION) NO_SEMIJOIN(@subq2) */ * 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 NULL ALL a NULL NULL NULL 3 100.00 Using where; Start temporary 1 PRIMARY t1 NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; End temporary; Using join buffer (Block Nested Loop) 3 DEPENDENT SUBQUERY t2 NULL index_subquery a a 4 func 1 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq2`) NO_SEMIJOIN(@`subq1` FIRSTMATCH, MATERIALIZATION) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) where ((`test`.`t1`.`a` = `test`.`t3`.`a`) and <in_optimizer>(`test`.`t3`.`b`,<exists>(<index_lookup>(<cache>(`test`.`t3`.`b`) in t2 on a)))) LooseScan can not be used since index scan would not be "covering" EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq1 FIRSTMATCH, MATERIALIZATION, DUPSWEEDOUT) NO_SEMIJOIN(@subq2) */ * 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 NULL ALL a NULL NULL NULL 3 100.00 Using where; Start temporary 1 PRIMARY t1 NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; End temporary; Using join buffer (Block Nested Loop) 3 DEPENDENT SUBQUERY t2 NULL index_subquery a a 4 func 1 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq2`) NO_SEMIJOIN(@`subq1` FIRSTMATCH, MATERIALIZATION, DUPSWEEDOUT) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) where ((`test`.`t1`.`a` = `test`.`t3`.`a`) and <in_optimizer>(`test`.`t3`.`b`,<exists>(<index_lookup>(<cache>(`test`.`t3`.`b`) in t2 on a)))) Allow all stragies except default EXPLAIN SELECT /*+ SEMIJOIN(@subq1 MATERIALIZATION, DUPSWEEDOUT, LOOSESCAN) NO_SEMIJOIN(@subq2) */ * 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 NULL ALL PRIMARY NULL NULL NULL 4 100.00 Using where 1 PRIMARY <subquery2> NULL eq_ref <auto_key> <auto_key> 4 test.t1.a 1 100.00 NULL 2 MATERIALIZED t3 NULL ALL a NULL NULL NULL 3 100.00 Using where 3 DEPENDENT SUBQUERY t2 NULL index_subquery a a 4 func 1 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq2`) SEMIJOIN(@`subq1` LOOSESCAN, MATERIALIZATION, DUPSWEEDOUT) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) where ((`<subquery2>`.`a` = `test`.`t1`.`a`) and <in_optimizer>(`test`.`t3`.`b`,<exists>(<index_lookup>(<cache>(`test`.`t3`.`b`) in t2 on a)))) Force a particular strategy EXPLAIN SELECT /*+ SEMIJOIN(@subq1 DUPSWEEDOUT) NO_SEMIJOIN(@subq2) */ * 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 NULL ALL a NULL NULL NULL 3 100.00 Using where; Start temporary 1 PRIMARY t1 NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; End temporary; Using join buffer (Block Nested Loop) 3 DEPENDENT SUBQUERY t2 NULL index_subquery a a 4 func 1 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq2`) SEMIJOIN(@`subq1` DUPSWEEDOUT) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) where ((`test`.`t1`.`a` = `test`.`t3`.`a`) and <in_optimizer>(`test`.`t3`.`b`,<exists>(<index_lookup>(<cache>(`test`.`t3`.`b`) in t2 on a)))) Turn off semijoin for both subqueries EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq1) NO_SEMIJOIN(@subq2) */ * 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 4 100.00 Using where 2 DEPENDENT SUBQUERY t3 NULL index_subquery a a 4 func 1 100.00 Using where 3 DEPENDENT SUBQUERY t2 NULL index_subquery a a 4 func 1 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq2`) NO_SEMIJOIN(@`subq1`) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where <in_optimizer>(`test`.`t1`.`a`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`a`) in t3 on a where (<in_optimizer>(`test`.`t3`.`b`,<exists>(<index_lookup>(<cache>(`test`.`t3`.`b`) in t2 on a))) and (<cache>(`test`.`t1`.`a`) = `test`.`t3`.`a`))))) Test hints with prepared statements PREPARE stmt1 FROM "EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; Start temporary 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; Using join buffer (Block Nested Loop) 1 SIMPLE t2 NULL ref a a 4 test.t1.b 1 100.00 Using index; End temporary Warnings: Note 1003 /* select#1 */ 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`.`t2`.`a` = `test`.`t1`.`b`) and (`test`.`t1`.`a` = `test`.`t3`.`a`)) EXECUTE stmt1; id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; Start temporary 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; Using join buffer (Block Nested Loop) 1 SIMPLE t2 NULL ref a a 4 test.t1.b 1 100.00 Using index; End temporary Warnings: Note 1003 /* select#1 */ 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`.`t2`.`a` = `test`.`t1`.`b`) and (`test`.`t1`.`a` = `test`.`t3`.`a`)) DEALLOCATE PREPARE stmt1; Another Prepared Statement test PREPARE stmt1 FROM "EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq1) SEMIJOIN(@subq2 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))"; EXECUTE stmt1; id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 4 100.00 Using where 2 SUBQUERY t2 NULL index a a 4 NULL 4 100.00 Using index; LooseScan 2 SUBQUERY t3 NULL ALL a NULL NULL NULL 3 33.33 Using where; Using join buffer (Block Nested Loop) Warnings: Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`subq2` LOOSESCAN) NO_SEMIJOIN(@`subq1`) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where <in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (/* select#2 */ select /*+ QB_NAME(`subq1`) */ `test`.`t3`.`a` from `test`.`t3` semi join (`test`.`t2`) where (`test`.`t3`.`b` = `test`.`t2`.`a`) ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on <auto_key> where ((`test`.`t1`.`a` = `materialized-subquery`.`a`))))) EXECUTE stmt1; id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 4 100.00 Using where 2 SUBQUERY t2 NULL index a a 4 NULL 4 100.00 Using index; LooseScan 2 SUBQUERY t3 NULL ALL a NULL NULL NULL 3 33.33 Using where; Using join buffer (Block Nested Loop) Warnings: Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`subq2` LOOSESCAN) NO_SEMIJOIN(@`subq1`) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where <in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (/* select#2 */ select /*+ QB_NAME(`subq1`) */ `test`.`t3`.`a` from `test`.`t3` semi join (`test`.`t2`) where (`test`.`t3`.`b` = `test`.`t2`.`a`) ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on <auto_key> where ((`test`.`t1`.`a` = `materialized-subquery`.`a`))))) 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 SELECT * FROM t2 WHERE t2.a IN (SELECT a FROM t1); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 NULL index NULL a 4 NULL 4 100.00 Using where; Using index 2 DEPENDENT SUBQUERY t1 NULL 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 <in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on PRIMARY))) This should not change anything EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq) */ a FROM t1); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 NULL index NULL a 4 NULL 4 100.00 Using where; Using index 2 DEPENDENT SUBQUERY t1 NULL 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 <in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on PRIMARY))) Force semijoin EXPLAIN SELECT /*+ SEMIJOIN(@subq) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq) */ a FROM t1); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using index 1 SIMPLE t1 NULL eq_ref PRIMARY PRIMARY 4 test.t2.a 1 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`subq`) */ `test`.`t2`.`a` AS `a` from `test`.`t1` join `test`.`t2` where (`test`.`t1`.`a` = `test`.`t2`.`a`) Setting strategy should still force semijoin Strategy is ignored since table pull-out is done EXPLAIN SELECT /*+ SEMIJOIN(@subq FIRSTMATCH) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq) */ a FROM t1); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using index 1 SIMPLE t1 NULL eq_ref PRIMARY PRIMARY 4 test.t2.a 1 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`subq` FIRSTMATCH) */ `test`.`t2`.`a` AS `a` from `test`.`t1` join `test`.`t2` where (`test`.`t1`.`a` = `test`.`t2`.`a`) Query with two sub-queries EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 NULL ALL NULL NULL NULL NULL 3 100.00 Using where 3 DEPENDENT SUBQUERY ty NULL unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index 2 DEPENDENT SUBQUERY tx NULL 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 (<in_optimizer>(`test`.`t3`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t3`.`a`) in t1 on PRIMARY))) and <in_optimizer>(`test`.`t3`.`b`,<exists>(<primary_index_lookup>(<cache>(`test`.`t3`.`b`) in t1 on PRIMARY)))) SEMIJOIN transformation for first subquery EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 NULL ALL a NULL NULL NULL 3 100.00 Using where 1 PRIMARY tx NULL eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 Using index 3 DEPENDENT SUBQUERY ty NULL 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 <in_optimizer>(`test`.`t3`.`b`,<exists>(<primary_index_lookup>(<cache>(`test`.`t3`.`b`) in t1 on PRIMARY)))) SEMIJOIN transformation for latter subquery EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 NULL ALL NULL NULL NULL NULL 3 100.00 Using where 1 PRIMARY ty NULL eq_ref PRIMARY PRIMARY 4 test.t3.b 1 100.00 Using index 2 DEPENDENT SUBQUERY tx NULL 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 <in_optimizer>(`test`.`t3`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t3`.`a`) in t1 on PRIMARY)))) SEMIJOIN transformation for both subqueries EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE tx NULL index PRIMARY PRIMARY 4 NULL 4 100.00 Using index 1 SIMPLE t3 NULL ALL a NULL NULL NULL 3 33.33 Using where; Using join buffer (Block Nested Loop) 1 SIMPLE ty NULL eq_ref PRIMARY PRIMARY 4 test.t3.b 1 100.00 Using index Warnings: Note 1003 /* select#1 */ 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`.`ty`.`a` = `test`.`t3`.`b`) and (`test`.`t3`.`a` = `test`.`tx`.`a`)) Query with nested sub-queries EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 NULL ALL NULL NULL NULL NULL 3 100.00 Using where 2 DEPENDENT SUBQUERY tx NULL unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using where 3 DEPENDENT SUBQUERY ty NULL 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 <in_optimizer>(`test`.`t3`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t3`.`a`) in t1 on PRIMARY where (<in_optimizer>(`test`.`tx`.`b`,<exists>(<primary_index_lookup>(<cache>(`test`.`tx`.`b`) in t1 on PRIMARY))) and (<cache>(`test`.`t3`.`a`) = `test`.`tx`.`a`))))) SEMIJOIN transformation for outer subquery EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 NULL ALL a NULL NULL NULL 3 100.00 NULL 1 PRIMARY tx NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; Using join buffer (Block Nested Loop) 3 SUBQUERY ty NULL index PRIMARY PRIMARY 4 NULL 4 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 <in_optimizer>(`test`.`tx`.`b`,`test`.`tx`.`b` in ( <materialize> (/* select#3 */ select /*+ QB_NAME(`subq2`) */ `test`.`ty`.`a` from `test`.`t1` `ty` where 1 ), <primary_index_lookup>(`test`.`tx`.`b` in <temporary table> on <auto_key> where ((`test`.`tx`.`b` = `materialized-subquery`.`a`)))))) SEMIJOIN transformation for inner-most subquery EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 NULL ALL NULL NULL NULL NULL 3 100.00 Using where 2 DEPENDENT SUBQUERY tx NULL eq_ref PRIMARY PRIMARY 4 func 1 100.00 Using where 2 DEPENDENT SUBQUERY ty NULL 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 <in_optimizer>(`test`.`t3`.`a`,<exists>(/* select#2 */ select /*+ QB_NAME(`subq1`) */ 1 from `test`.`t1` `ty` join `test`.`t1` `tx` where ((`test`.`ty`.`a` = `test`.`tx`.`b`) and (<cache>(`test`.`t3`.`a`) = `test`.`tx`.`a`)))) SEMIJOIN transformation for both EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL ALL a NULL NULL NULL 3 100.00 NULL 1 SIMPLE tx NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; Using join buffer (Block Nested Loop) 1 SIMPLE ty NULL eq_ref PRIMARY PRIMARY 4 test.tx.b 1 100.00 Using index Warnings: Note 1003 /* select#1 */ 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`.`tx`.`a` = `test`.`t3`.`a`) and (`test`.`ty`.`a` = `test`.`tx`.`b`)) 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 SELECT * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using index 1 SIMPLE t3 NULL ref a a 4 test.t2.a 1 100.00 Using index; FirstMatch(t2) Warnings: Note 1003 /* select#1 */ 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 should still be SELECTed EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq1 LOOSESCAN) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using index 1 SIMPLE t3 NULL ref a a 4 test.t2.a 1 100.00 Using index; FirstMatch(t2) Warnings: Note 1003 /* select#1 */ 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, MatLookup should then be used EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq1 FIRSTMATCH) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using where; Using index 1 SIMPLE <subquery2> NULL eq_ref <auto_key> <auto_key> 4 test.t2.a 1 100.00 NULL 2 MATERIALIZED t3 NULL index a a 4 NULL 3 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq1` FIRSTMATCH) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where (`<subquery2>`.`a` = `test`.`t2`.`a`) Let's also turn off Materialization, DuplicateWeedout should then be used EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq1 FIRSTMATCH, MATERIALIZATION) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; Start temporary 1 SIMPLE t2 NULL ref a a 4 test.t3.a 1 100.00 Using index; End temporary Warnings: Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq1` FIRSTMATCH, MATERIALIZATION) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where (`test`.`t2`.`a` = `test`.`t3`.`a`) Let's force LooseScan back on EXPLAIN SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; LooseScan 1 SIMPLE t2 NULL ref a a 4 test.t3.a 1 100.00 Using index Warnings: Note 1003 /* select#1 */ 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 SELECT /*+ SEMIJOIN(@subq1 MATERIALIZATION) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using where; Using index 1 SIMPLE <subquery2> NULL eq_ref <auto_key> <auto_key> 4 test.t2.a 1 100.00 NULL 2 MATERIALIZED t3 NULL index a a 4 NULL 3 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`subq1` MATERIALIZATION) */ `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t3`) where (`<subquery2>`.`a` = `test`.`t2`.`a`) If LooseScan is among candidates, it is used even if originally disabled EXPLAIN SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN, DUPSWEEDOUT) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; LooseScan 1 SIMPLE t2 NULL ref a a 4 test.t3.a 1 100.00 Using index Warnings: Note 1003 /* select#1 */ 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 SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN, MATERIALIZATION, DUPSWEEDOUT) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; LooseScan 1 SIMPLE t2 NULL ref a a 4 test.t3.a 1 100.00 Using index Warnings: Note 1003 /* select#1 */ 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 SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN, FIRSTMATCH, MATERIALIZATION, DUPSWEEDOUT) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; LooseScan 1 SIMPLE t2 NULL ref a a 4 test.t3.a 1 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ 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`) Disable another strategy SET optimizer_switch='firstmatch=off'; Turn on FirstMatch, but not LooseScan on with hint EXPLAIN SELECT /*+ SEMIJOIN(@subq1 FIRSTMATCH, MATERIALIZATION, DUPSWEEDOUT) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using index 1 SIMPLE t3 NULL ref a a 4 test.t2.a 1 100.00 Using index; FirstMatch(t2) Warnings: Note 1003 /* select#1 */ 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 SELECT /*+ NO_SEMIJOIN(@subq1 MATERIALIZATION, DUPSWEEDOUT) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; Start temporary 1 SIMPLE t2 NULL ref a a 4 test.t3.a 1 100.00 Using index; End temporary Warnings: Note 1003 /* select#1 */ 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 SELECT * FROM t1 WHERE t1.b IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3 WHERE t3.b = t1.a); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL ALL a NULL NULL NULL 3 100.00 Start temporary 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; End temporary; Using join buffer (Block Nested Loop) Warnings: Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1 Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) where ((`test`.`t1`.`b` = `test`.`t3`.`a`) and (`test`.`t1`.`a` = `test`.`t3`.`b`)) Turn off all applicable strategies. DuplicateWeedout should still be used EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL ALL a NULL NULL NULL 3 100.00 Start temporary 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; End temporary; Using join buffer (Block Nested Loop) Warnings: Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1 Note 1003 /* select#1 */ 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`.`b` = `test`.`t3`.`a`) and (`test`.`t1`.`a` = `test`.`t3`.`b`)) Reverse which strategies are allowed with hint EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 100.00 NULL 1 SIMPLE t3 NULL ALL a NULL NULL NULL 3 33.33 Using where; FirstMatch(t1); Using join buffer (Block Nested Loop) Warnings: Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1 Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`subq1` FIRSTMATCH, LOOSESCAN) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) where ((`test`.`t3`.`a` = `test`.`t1`.`b`) and (`test`.`t3`.`b` = `test`.`t1`.`a`)) Default for this query is Loosecan for first and FirstMatch for latter Since both strategies are disabled, will now use DuplicateWeedout EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; Start temporary 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; Using join buffer (Block Nested Loop) 1 SIMPLE t2 NULL ref a a 4 test.t1.b 1 100.00 Using index; End temporary Warnings: Note 1003 /* select#1 */ select `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`) and (`test`.`t1`.`a` = `test`.`t3`.`a`)) Allowing LooseScan and FirstMatch and optimizer_switch is ignored EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; LooseScan 1 SIMPLE t1 NULL eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 Using where 1 SIMPLE t2 NULL ref a a 4 test.t1.b 1 100.00 Using index; FirstMatch(t1) Warnings: Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`subq1` FIRSTMATCH, LOOSESCAN) 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`.`t2`.`a` = `test`.`t1`.`b`) and (`test`.`t1`.`a` = `test`.`t3`.`a`)) Forcing a disabled strategy for one EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using index; Start temporary 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; End temporary; Using join buffer (Block Nested Loop) 1 SIMPLE t3 NULL ref a a 4 test.t1.a 1 100.00 Using index; FirstMatch(t1) Warnings: Note 1003 /* select#1 */ 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`.`t1`.`b` = `test`.`t2`.`a`) and (`test`.`t3`.`a` = `test`.`t1`.`a`)) Forcing same strategy for both EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 100.00 Using where 1 SIMPLE t3 NULL ref a a 4 test.t1.a 1 100.00 Using index; FirstMatch(t1) 1 SIMPLE t2 NULL ref a a 4 test.t1.b 1 100.00 Using index; FirstMatch(t3) Warnings: Note 1003 /* select#1 */ 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`.`t2`.`a` = `test`.`t1`.`b`) and (`test`.`t3`.`a` = `test`.`t1`.`a`)) Swap strategies compared to default EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using index; LooseScan 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; Using join buffer (Block Nested Loop) 1 SIMPLE t3 NULL ref a a 4 test.t1.a 1 100.00 Using index; FirstMatch(t1) Warnings: Note 1003 /* select#1 */ 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`.`t1`.`b` = `test`.`t2`.`a`) and (`test`.`t3`.`a` = `test`.`t1`.`a`)) Different subsets of strategies for different subqueries EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; LooseScan 1 SIMPLE t1 NULL eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 Using where 1 SIMPLE <subquery3> NULL eq_ref <auto_key> <auto_key> 4 test.t1.b 1 100.00 NULL 3 MATERIALIZED t2 NULL index a a 4 NULL 4 100.00 Using index Warnings: Note 1003 /* select#1 */ 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 ((`<subquery3>`.`a` = `test`.`t1`.`b`) and (`test`.`t1`.`a` = `test`.`t3`.`a`)) Turn off DuplicateWeedout for both. Materialization is left EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 100.00 Using where 1 SIMPLE <subquery2> NULL eq_ref <auto_key> <auto_key> 4 test.t1.a 1 100.00 NULL 1 SIMPLE <subquery3> NULL eq_ref <auto_key> <auto_key> 4 test.t1.b 1 100.00 NULL 2 MATERIALIZED t3 NULL index a a 4 NULL 3 100.00 Using index 3 MATERIALIZED t2 NULL index a a 4 NULL 4 100.00 Using index Warnings: Note 1003 /* select#1 */ 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 ((`<subquery3>`.`a` = `test`.`t1`.`b`) and (`<subquery2>`.`a` = `test`.`t1`.`a`)) Forcing materialization should have same effect EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 100.00 Using where 1 SIMPLE <subquery2> NULL eq_ref <auto_key> <auto_key> 4 test.t1.a 1 100.00 NULL 1 SIMPLE <subquery3> NULL eq_ref <auto_key> <auto_key> 4 test.t1.b 1 100.00 NULL 2 MATERIALIZED t3 NULL index a a 4 NULL 3 100.00 Using index 3 MATERIALIZED t2 NULL index a a 4 NULL 4 100.00 Using index Warnings: Note 1003 /* select#1 */ 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 ((`<subquery3>`.`a` = `test`.`t1`.`b`) and (`<subquery2>`.`a` = `test`.`t1`.`a`)) Turn off DuplicateWeedout for first. MatLookup is used for both EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 100.00 Using where 1 SIMPLE <subquery2> NULL eq_ref <auto_key> <auto_key> 4 test.t1.a 1 100.00 NULL 1 SIMPLE <subquery3> NULL eq_ref <auto_key> <auto_key> 4 test.t1.b 1 100.00 NULL 2 MATERIALIZED t3 NULL index a a 4 NULL 3 100.00 Using index 3 MATERIALIZED t2 NULL index a a 4 NULL 4 100.00 Using index Warnings: Note 1003 /* select#1 */ 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 ((`<subquery3>`.`a` = `test`.`t1`.`b`) and (`<subquery2>`.`a` = `test`.`t1`.`a`)) Turn off DuplicateWeedout for second. Same effect. EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 100.00 Using where 1 SIMPLE <subquery2> NULL eq_ref <auto_key> <auto_key> 4 test.t1.a 1 100.00 NULL 1 SIMPLE <subquery3> NULL eq_ref <auto_key> <auto_key> 4 test.t1.b 1 100.00 NULL 2 MATERIALIZED t3 NULL index a a 4 NULL 3 100.00 Using index 3 MATERIALIZED t2 NULL index a a 4 NULL 4 100.00 Using index Warnings: Note 1003 /* select#1 */ 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 ((`<subquery3>`.`a` = `test`.`t1`.`b`) and (`<subquery2>`.`a` = `test`.`t1`.`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 SELECT /*+ NO_SEMIJOIN(@subq1 LOOSESCAN, FIRSTMATCH, MATERIALIZATION) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; Start temporary 1 SIMPLE t2 NULL ref a a 4 test.t3.a 1 100.00 Using index; End temporary Warnings: Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq1` FIRSTMATCH, LOOSESCAN, 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 SELECT * FROM t1 WHERE t1.b IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3 WHERE t3.b = t1.a); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 100.00 NULL 1 SIMPLE t3 NULL ALL a NULL NULL NULL 3 33.33 Using where; FirstMatch(t1); Using join buffer (Block Nested Loop) Warnings: Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1 Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) where ((`test`.`t3`.`a` = `test`.`t1`.`b`) and (`test`.`t3`.`b` = `test`.`t1`.`a`)) Turn off all applicable strategies. DuplicateWeedout should be used EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL ALL a NULL NULL NULL 3 100.00 Start temporary 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; End temporary; Using join buffer (Block Nested Loop) Warnings: Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1 Note 1003 /* select#1 */ 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`.`b` = `test`.`t3`.`a`) and (`test`.`t1`.`a` = `test`.`t3`.`b`)) Similar with SEMIJOIN hint EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL ALL a NULL NULL NULL 3 100.00 Start temporary 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; End temporary; Using join buffer (Block Nested Loop) Warnings: Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1 Note 1003 /* select#1 */ 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`.`b` = `test`.`t3`.`a`) and (`test`.`t1`.`a` = `test`.`t3`.`b`)) Disable all strategies SET optimizer_switch='firstmatch=off,loosescan=off,materialization=off,duplicateweedout=off'; DuplicateWeedout is then used EXPLAIN SELECT * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; Start temporary 1 SIMPLE t2 NULL ref a a 4 test.t3.a 1 100.00 Using index; End temporary Warnings: Note 1003 /* select#1 */ 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 SELECT /*+ NO_SEMIJOIN(@subq1 LOOSESCAN, DUPSWEEDOUT) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; Start temporary 1 SIMPLE t2 NULL ref a a 4 test.t3.a 1 100.00 Using index; End temporary Warnings: Note 1003 /* select#1 */ 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 SELECT /*+ SEMIJOIN(@subq1 FIRSTMATCH, MATERIALIZATION) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using index 1 SIMPLE t3 NULL ref a a 4 test.t2.a 1 100.00 Using index; FirstMatch(t2) Warnings: Note 1003 /* select#1 */ 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 DupliateWeedout EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL ALL a NULL NULL NULL 3 100.00 Start temporary 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; End temporary; Using join buffer (Block Nested Loop) Warnings: Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1 Note 1003 /* select#1 */ 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`.`b` = `test`.`t3`.`a`) and (`test`.`t1`.`a` = `test`.`t3`.`b`)) Turning on FirstMatch should give FirstMatch EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 100.00 NULL 1 SIMPLE t3 NULL ALL a NULL NULL NULL 3 33.33 Using where; FirstMatch(t1); Using join buffer (Block Nested Loop) Warnings: Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1 Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`subq1` FIRSTMATCH, LOOSESCAN) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) where ((`test`.`t3`.`a` = `test`.`t1`.`b`) and (`test`.`t3`.`b` = `test`.`t1`.`a`)) SET optimizer_switch = default; Test that setting optimizer_switch after prepare will change strategy PREPARE stmt1 FROM "EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; Start temporary 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; Using join buffer (Block Nested Loop) 1 SIMPLE t2 NULL ref a a 4 test.t1.b 1 100.00 Using index; End temporary Warnings: Note 1003 /* select#1 */ 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`.`t2`.`a` = `test`.`t1`.`b`) and (`test`.`t1`.`a` = `test`.`t3`.`a`)) SET optimizer_switch = 'duplicateweedout=off'; Will now use materialization EXECUTE stmt1; id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 100.00 Using where 1 SIMPLE <subquery2> NULL eq_ref <auto_key> <auto_key> 4 test.t1.a 1 100.00 NULL 1 SIMPLE <subquery3> NULL eq_ref <auto_key> <auto_key> 4 test.t1.b 1 100.00 NULL 2 MATERIALIZED t3 NULL index a a 4 NULL 3 100.00 Using index 3 MATERIALIZED t2 NULL index a a 4 NULL 4 100.00 Using index Warnings: Note 1003 /* select#1 */ 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 ((`<subquery3>`.`a` = `test`.`t1`.`b`) and (`<subquery2>`.`a` = `test`.`t1`.`a`)) SET optimizer_switch = 'duplicateweedout=on'; Turn DuplicateWeedout back on EXECUTE stmt1; id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; Start temporary 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; Using join buffer (Block Nested Loop) 1 SIMPLE t2 NULL ref a a 4 test.t1.b 1 100.00 Using index; End temporary Warnings: Note 1003 /* select#1 */ 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`.`t2`.`a` = `test`.`t1`.`b`) and (`test`.`t1`.`a` = `test`.`t3`.`a`)) 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 SELECT * FROM t2 WHERE t2.a IN (SELECT /*+ NO_SEMIJOIN() SEMIJOIN() */ a FROM t1); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 NULL index NULL a 4 NULL 4 100.00 Using where; Using index 2 DEPENDENT SUBQUERY t1 NULL unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index Warnings: Warning 3126 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 <in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on PRIMARY))) Try opposite order EXPLAIN SELECT * FROM t2 WHERE t2.a IN (SELECT /*+ SEMIJOIN() NO_SEMIJOIN() */ a FROM t1); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using index 1 SIMPLE t1 NULL eq_ref PRIMARY PRIMARY 4 test.t2.a 1 100.00 Using index Warnings: Warning 3126 Hint NO_SEMIJOIN( ) is ignored as conflicting/duplicated Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`select#2`) */ `test`.`t2`.`a` AS `a` from `test`.`t1` join `test`.`t2` where (`test`.`t1`.`a` = `test`.`t2`.`a`) Specify at different levels, hint inside block has effect EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq) SEMIJOIN() */ a FROM t1); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using index 1 SIMPLE t1 NULL eq_ref PRIMARY PRIMARY 4 test.t2.a 1 100.00 Using index Warnings: Warning 3126 Hint NO_SEMIJOIN(@`subq` ) is ignored as conflicting/duplicated Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`subq`) */ `test`.`t2`.`a` AS `a` from `test`.`t1` join `test`.`t2` where (`test`.`t1`.`a` = `test`.`t2`.`a`) Specify at different levels, opposite order EXPLAIN SELECT /*+ SEMIJOIN(@subq) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq) NO_SEMIJOIN() */ a FROM t1); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 NULL index NULL a 4 NULL 4 100.00 Using where; Using index 2 DEPENDENT SUBQUERY t1 NULL unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index Warnings: Warning 3126 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 <in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on PRIMARY))) Duplicate hints also gives warning, but hint has effect EXPLAIN SELECT /*+ SEMIJOIN(@subq) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq) SEMIJOIN() */ a FROM t1); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using index 1 SIMPLE t1 NULL eq_ref PRIMARY PRIMARY 4 test.t2.a 1 100.00 Using index Warnings: Warning 3126 Hint SEMIJOIN(@`subq` ) is ignored as conflicting/duplicated Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`subq`) */ `test`.`t2`.`a` AS `a` from `test`.`t1` join `test`.`t2` where (`test`.`t1`.`a` = `test`.`t2`.`a`) EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq) NO_SEMIJOIN() */ a FROM t1); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 NULL index NULL a 4 NULL 4 100.00 Using where; Using index 2 DEPENDENT SUBQUERY t1 NULL unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index Warnings: Warning 3126 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 <in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on PRIMARY))) Multiple subqueries with conflicting hints EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 NULL index a a 4 NULL 4 100.00 Using index; LooseScan 1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 4 25.00 Using where; Using join buffer (Block Nested Loop) 2 SUBQUERY t3 NULL index a a 4 NULL 3 100.00 Using index Warnings: Warning 3126 Hint SEMIJOIN(@`subq1` LOOSESCAN) is ignored as conflicting/duplicated Warning 3126 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`.`t1`.`b` = `test`.`t2`.`a`) and <in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (/* select#2 */ select /*+ QB_NAME(`subq1`) */ `test`.`t3`.`a` from `test`.`t3` where 1 ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on <auto_key> where ((`test`.`t1`.`a` = `materialized-subquery`.`a`)))))) EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using index; LooseScan 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; Using join buffer (Block Nested Loop) 1 SIMPLE t3 NULL ref a a 4 test.t1.a 1 100.00 Using index; FirstMatch(t1) Warnings: Warning 3126 Hint SEMIJOIN(@`subq1` LOOSESCAN) is ignored as conflicting/duplicated Warning 3126 Hint SEMIJOIN(@`subq2` FIRSTMATCH) is ignored as conflicting/duplicated Note 1003 /* select#1 */ 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`.`t1`.`b` = `test`.`t2`.`a`) and (`test`.`t3`.`a` = `test`.`t1`.`a`)) Conflicting hints in same hint comment EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; LooseScan 1 SIMPLE t1 NULL eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 Using where 1 SIMPLE t2 NULL ref a a 4 test.t1.b 1 100.00 Using index; FirstMatch(t1) Warnings: Warning 3126 Hint SEMIJOIN(@`subq1` FIRSTMATCH) is ignored as conflicting/duplicated Note 1003 /* select#1 */ 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`.`t2`.`a` = `test`.`t1`.`b`) and (`test`.`t1`.`a` = `test`.`t3`.`a`)) EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; LooseScan 1 SIMPLE t1 NULL eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 Using where 1 SIMPLE t2 NULL ref a a 4 test.t1.b 1 100.00 Using index; FirstMatch(t1) Warnings: Warning 3126 Hint NO_SEMIJOIN(@`subq1` LOOSESCAN) is ignored as conflicting/duplicated Note 1003 /* select#1 */ 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`.`t2`.`a` = `test`.`t1`.`b`) and (`test`.`t1`.`a` = `test`.`t3`.`a`)) EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using index; LooseScan 1 SIMPLE t1 NULL ALL PRIMARY NULL NULL NULL 4 25.00 Using where; Using join buffer (Block Nested Loop) 1 SIMPLE t3 NULL ref a a 4 test.t1.a 1 100.00 Using index; FirstMatch(t1) Warnings: Warning 3126 Hint NO_SEMIJOIN(@`subq1` FIRSTMATCH) is ignored as conflicting/duplicated Note 1003 /* select#1 */ 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`.`t1`.`b` = `test`.`t2`.`a`) and (`test`.`t3`.`a` = `test`.`t1`.`a`)) Non-supported strategies should give warnings EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 NULL index a a 4 NULL 3 100.00 Using index; LooseScan 1 SIMPLE t1 NULL eq_ref PRIMARY PRIMARY 4 test.t3.a 1 100.00 Using where 1 SIMPLE t2 NULL ref a a 4 test.t1.b 1 100.00 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#1 */ select `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`) and (`test`.`t1`.`a` = `test`.`t3`.`a`)) SUBQUERY tests SUBQUERY should disable SEMIJOIN and use specified subquery strategy EXPLAIN SELECT * FROM t2 WHERE t2.a IN (SELECT /*+ SUBQUERY(INTOEXISTS) */ a FROM t1); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 NULL index NULL a 4 NULL 4 100.00 Using where; Using index 2 DEPENDENT SUBQUERY t1 NULL 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 <in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 NULL index NULL a 4 NULL 4 100.00 Using where; Using index 2 SUBQUERY t1 NULL index PRIMARY 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 <in_optimizer>(`test`.`t2`.`a`,`test`.`t2`.`a` in ( <materialize> (/* select#2 */ select /*+ QB_NAME(`subq`) */ `test`.`t1`.`a` from `test`.`t1` where 1 ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on <auto_key> where ((`test`.`t2`.`a` = `materialized-subquery`.`a`))))) Query with two subqueries EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 NULL ALL NULL NULL NULL NULL 3 100.00 Using where 3 SUBQUERY ty NULL index PRIMARY PRIMARY 4 NULL 4 100.00 Using index 2 DEPENDENT SUBQUERY tx NULL 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 (<in_optimizer>(`test`.`t3`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t3`.`a`) in t1 on PRIMARY))) and <in_optimizer>(`test`.`t3`.`b`,`test`.`t3`.`b` in ( <materialize> (/* select#3 */ select /*+ QB_NAME(`subq2`) */ `test`.`ty`.`a` from `test`.`t1` `ty` where 1 ), <primary_index_lookup>(`test`.`t3`.`b` in <temporary table> on <auto_key> where ((`test`.`t3`.`b` = `materialized-subquery`.`a`)))))) Query with nested sub-queries EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 NULL ALL NULL NULL NULL NULL 3 100.00 Using where 2 DEPENDENT SUBQUERY tx NULL unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using where 3 SUBQUERY ty NULL index PRIMARY 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 <in_optimizer>(`test`.`t3`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t3`.`a`) in t1 on PRIMARY where (<in_optimizer>(`test`.`tx`.`b`,`test`.`tx`.`b` in ( <materialize> (/* select#3 */ select /*+ QB_NAME(`subq2`) */ `test`.`ty`.`a` from `test`.`t1` `ty` where 1 ), <primary_index_lookup>(`test`.`tx`.`b` in <temporary table> on <auto_key> where ((`test`.`tx`.`b` = `materialized-subquery`.`a`))))) and (<cache>(`test`.`t3`.`a`) = `test`.`tx`.`a`))))) EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 NULL ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY tx NULL ALL PRIMARY NULL NULL NULL 4 100.00 Using where 3 DEPENDENT SUBQUERY ty NULL 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 <in_optimizer>(`test`.`t3`.`a`,`test`.`t3`.`a` in ( <materialize> (/* select#2 */ select /*+ QB_NAME(`subq1`) */ `test`.`tx`.`a` from `test`.`t1` `tx` where <in_optimizer>(`test`.`tx`.`b`,<exists>(<primary_index_lookup>(<cache>(`test`.`tx`.`b`) in t1 on PRIMARY))) ), <primary_index_lookup>(`test`.`t3`.`a` in <temporary table> on <auto_key> where ((`test`.`t3`.`a` = `materialized-subquery`.`a`))))) This query does not support SEMIJOIN. Materialization is default EXPLAIN SELECT * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq) */ min(a) FROM t1 group by a); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 NULL index NULL a 4 NULL 4 100.00 Using where; Using index 2 SUBQUERY t1 NULL index PRIMARY PRIMARY 4 NULL 4 100.00 Using index Warnings: Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,`test`.`t2`.`a` in ( <materialize> (/* select#2 */ select /*+ QB_NAME(`subq`) */ min(`test`.`t1`.`a`) from `test`.`t1` group by `test`.`t1`.`a` having 1 ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on <auto_key> where ((`test`.`t2`.`a` = `materialized-subquery`.`min(a)`))))) Use In-to-exists instead EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 NULL index NULL a 4 NULL 4 100.00 Using where; Using index 2 DEPENDENT SUBQUERY t1 NULL index PRIMARY PRIMARY 4 NULL 4 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ SUBQUERY(@`subq` INTOEXISTS) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,<exists>(/* select#2 */ select /*+ QB_NAME(`subq`) */ 1 from `test`.`t1` group by `test`.`t1`.`a` having (<cache>(`test`.`t2`.`a`) = <ref_null_helper>(min(`test`.`t1`.`a`))))) For this query In-to-exists is default EXPLAIN SELECT a, a IN (SELECT a FROM t1) FROM t2; id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 NULL index NULL a 4 NULL 4 100.00 Using index 2 DEPENDENT SUBQUERY t1 NULL unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index Warnings: Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a`,<in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on PRIMARY))) AS `a IN (SELECT a FROM t1)` from `test`.`t2` Force Subquery Materialization EXPLAIN SELECT a, a IN (SELECT /*+ SUBQUERY(MATERIALIZATION) */ a FROM t1) FROM t2; id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 NULL index NULL a 4 NULL 4 100.00 Using index 2 SUBQUERY t1 NULL index PRIMARY PRIMARY 4 NULL 4 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ SUBQUERY(@`select#2` MATERIALIZATION) */ `test`.`t2`.`a` AS `a`,<in_optimizer>(`test`.`t2`.`a`,`test`.`t2`.`a` in ( <materialize> (/* select#2 */ select `test`.`t1`.`a` from `test`.`t1` where 1 ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on <auto_key> where ((`test`.`t2`.`a` = `materialized-subquery`.`a`))))) AS `a IN (SELECT /*+ SUBQUERY(MATERIALIZATION) */ a FROM t1)` from `test`.`t2` EXPLAIN SELECT /*+ SUBQUERY(@subq MATERIALIZATION) */ a, a IN (SELECT /*+ QB_NAME(subq) */ a FROM t1) FROM t2; id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 NULL index NULL a 4 NULL 4 100.00 Using index 2 SUBQUERY t1 NULL index PRIMARY PRIMARY 4 NULL 4 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ SUBQUERY(@`subq` MATERIALIZATION) */ `test`.`t2`.`a` AS `a`,<in_optimizer>(`test`.`t2`.`a`,`test`.`t2`.`a` in ( <materialize> (/* select#2 */ select /*+ QB_NAME(`subq`) */ `test`.`t1`.`a` from `test`.`t1` where 1 ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on <auto_key> where ((`test`.`t2`.`a` = `materialized-subquery`.`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 SELECT * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq) */ sum(b) FROM t1 group by a); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 NULL index NULL a 4 NULL 4 100.00 Using where; Using index 2 DEPENDENT SUBQUERY t1 NULL index PRIMARY PRIMARY 4 NULL 4 100.00 NULL Warnings: Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,<exists>(/* select#2 */ select /*+ QB_NAME(`subq`) */ 1 from `test`.`t1` group by `test`.`t1`.`a` having (<cache>(`test`.`t2`.`a`) = <ref_null_helper>(sum(`test`.`t1`.`b`))))) Trying to force Subquery Materialization will not change anything EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 NULL index NULL a 4 NULL 4 100.00 Using where; Using index 2 DEPENDENT SUBQUERY t1 NULL index PRIMARY PRIMARY 4 NULL 4 100.00 NULL Warnings: Note 1003 /* select#1 */ select /*+ SUBQUERY(@`subq` MATERIALIZATION) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,<exists>(/* select#2 */ select /*+ QB_NAME(`subq`) */ 1 from `test`.`t1` group by `test`.`t1`.`a` having (<cache>(`test`.`t2`.`a`) = <ref_null_helper>(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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 4 100.00 Using where 3 DEPENDENT SUBQUERY t2 NULL index_subquery a a 4 func 1 100.00 Using index 2 SUBQUERY t3 NULL index a a 4 NULL 3 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ SUBQUERY(@`subq1` MATERIALIZATION) SUBQUERY(@`subq2` INTOEXISTS) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where (<in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (/* select#2 */ select /*+ QB_NAME(`subq1`) */ `test`.`t3`.`a` from `test`.`t3` where 1 ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on <auto_key> where ((`test`.`t1`.`a` = `materialized-subquery`.`a`))))) and <in_optimizer>(`test`.`t1`.`b`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`b`) in t2 on a)))) EXECUTE stmt1; id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 4 100.00 Using where 3 DEPENDENT SUBQUERY t2 NULL index_subquery a a 4 func 1 100.00 Using index 2 SUBQUERY t3 NULL index a a 4 NULL 3 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ SUBQUERY(@`subq1` MATERIALIZATION) SUBQUERY(@`subq2` INTOEXISTS) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where (<in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (/* select#2 */ select /*+ QB_NAME(`subq1`) */ `test`.`t3`.`a` from `test`.`t3` where 1 ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on <auto_key> where ((`test`.`t1`.`a` = `materialized-subquery`.`a`))))) and <in_optimizer>(`test`.`t1`.`b`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`b`) in t2 on a)))) DEALLOCATE PREPARE stmt1; Test optimizer_switch settings with SUBQUERY hint SET optimizer_switch='materialization=off'; This query will now use In-to-exist EXPLAIN SELECT * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq) */ min(a) FROM t1 group by a); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 NULL index NULL a 4 NULL 4 100.00 Using where; Using index 2 DEPENDENT SUBQUERY t1 NULL index PRIMARY PRIMARY 4 NULL 4 100.00 Using index Warnings: Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,<exists>(/* select#2 */ select /*+ QB_NAME(`subq`) */ 1 from `test`.`t1` group by `test`.`t1`.`a` having (<cache>(`test`.`t2`.`a`) = <ref_null_helper>(min(`test`.`t1`.`a`))))) Force it to use Materialization EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 NULL index NULL a 4 NULL 4 100.00 Using where; Using index 2 SUBQUERY t1 NULL index PRIMARY 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 <in_optimizer>(`test`.`t2`.`a`,`test`.`t2`.`a` in ( <materialize> (/* select#2 */ select /*+ QB_NAME(`subq`) */ min(`test`.`t1`.`a`) from `test`.`t1` group by `test`.`t1`.`a` having 1 ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on <auto_key> where ((`test`.`t2`.`a` = `materialized-subquery`.`min(a)`))))) SET optimizer_switch='materialization=on,subquery_materialization_cost_based=off'; This query will now use materialization EXPLAIN SELECT a, a IN (SELECT a FROM t1) FROM t2; id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 NULL index NULL a 4 NULL 4 100.00 Using index 2 SUBQUERY t1 NULL index PRIMARY PRIMARY 4 NULL 4 100.00 Using index Warnings: Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a`,<in_optimizer>(`test`.`t2`.`a`,`test`.`t2`.`a` in ( <materialize> (/* select#2 */ select `test`.`t1`.`a` from `test`.`t1` where 1 ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on <auto_key> where ((`test`.`t2`.`a` = `materialized-subquery`.`a`))))) AS `a IN (SELECT a FROM t1)` from `test`.`t2` Force In-to-exists EXPLAIN SELECT /*+ SUBQUERY(@subq INTOEXISTS) */ a, a IN (SELECT /*+ QB_NAME(subq) */ a FROM t1) FROM t2; id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 NULL index NULL a 4 NULL 4 100.00 Using index 2 DEPENDENT SUBQUERY t1 NULL unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index Warnings: Note 1003 /* select#1 */ select /*+ SUBQUERY(@`subq` INTOEXISTS) */ `test`.`t2`.`a` AS `a`,<in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on PRIMARY))) AS `a IN (SELECT /*+ QB_NAME(subq) */ a FROM t1)` from `test`.`t2` Specifying both strategies should give a warning EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE tx NULL index PRIMARY PRIMARY 4 NULL 4 100.00 Using index 1 SIMPLE t3 NULL ALL a NULL NULL NULL 3 33.33 Using where; Using join buffer (Block Nested Loop) 1 SIMPLE ty NULL 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 t3' at line 2 Note 1003 /* select#1 */ 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`.`t3`.`b`) and (`test`.`t3`.`a` = `test`.`tx`.`a`)) Non-supported strategies should give warnings EXPLAIN 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 partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE tx NULL index PRIMARY PRIMARY 4 NULL 4 100.00 Using index 1 SIMPLE t3 NULL ALL a NULL NULL NULL 3 33.33 Using where; Using join buffer (Block Nested Loop) 1 SIMPLE ty NULL 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 /*+ QB' at line 2 Note 1003 /* select#1 */ 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`.`t3`.`b`) and (`test`.`t3`.`a` = `test`.`tx`.`a`)) SET optimizer_switch= default; Specifying two SUBQUERY for same query block gives warning First has effect, second is ignored EXPLAIN SELECT * FROM t2 WHERE t2.a IN (SELECT /*+ SUBQUERY(MATERIALIZATION) SUBQUERY(INTOEXISTS) */ a FROM t1); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 NULL index NULL a 4 NULL 4 100.00 Using where; Using index 2 SUBQUERY t1 NULL index PRIMARY PRIMARY 4 NULL 4 100.00 Using index Warnings: Warning 3126 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 <in_optimizer>(`test`.`t2`.`a`,`test`.`t2`.`a` in ( <materialize> (/* select#2 */ select `test`.`t1`.`a` from `test`.`t1` where 1 ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on <auto_key> where ((`test`.`t2`.`a` = `materialized-subquery`.`a`))))) Try opposite order EXPLAIN SELECT * FROM t2 WHERE t2.a IN (SELECT /*+ SUBQUERY(INTOEXISTS) SUBQUERY(MATERIALIZATION) */ a FROM t1); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 NULL index NULL a 4 NULL 4 100.00 Using where; Using index 2 DEPENDENT SUBQUERY t1 NULL unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index Warnings: Warning 3126 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 <in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on PRIMARY))) Specify at different levels, hint inside block has effect EXPLAIN SELECT /*+ SUBQUERY(@subq MATERIALIZATION) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq) SUBQUERY(INTOEXISTS) */ a FROM t1); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 NULL index NULL a 4 NULL 4 100.00 Using where; Using index 2 DEPENDENT SUBQUERY t1 NULL unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index Warnings: Warning 3126 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 <in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on PRIMARY))) Specify at different levels, opposite order EXPLAIN SELECT /*+ SUBQUERY(@subq INTOEXISTS) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq) SUBQUERY(MATERIALIZATION) */ a FROM t1); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 NULL index NULL a 4 NULL 4 100.00 Using where; Using index 2 SUBQUERY t1 NULL index PRIMARY PRIMARY 4 NULL 4 100.00 Using index Warnings: Warning 3126 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 <in_optimizer>(`test`.`t2`.`a`,`test`.`t2`.`a` in ( <materialize> (/* select#2 */ select /*+ QB_NAME(`subq`) */ `test`.`t1`.`a` from `test`.`t1` where 1 ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on <auto_key> where ((`test`.`t2`.`a` = `materialized-subquery`.`a`))))) Specifying combinations of SUBQUERY and SEMIJOIN/NO_SEMIJOIN for same query block gives warning First has effect, second is ignored EXPLAIN SELECT * FROM t2 WHERE t2.a IN (SELECT /*+ SUBQUERY(INTOEXISTS) SEMIJOIN() */ a FROM t1); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 NULL index NULL a 4 NULL 4 100.00 Using where; Using index 2 DEPENDENT SUBQUERY t1 NULL unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index Warnings: Warning 3126 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 <in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on PRIMARY))) Try opposite order EXPLAIN SELECT * FROM t2 WHERE t2.a IN (SELECT /*+ NO_SEMIJOIN() SUBQUERY(MATERIALIZATION) */ a FROM t1); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 NULL index NULL a 4 NULL 4 100.00 Using where; Using index 2 DEPENDENT SUBQUERY t1 NULL unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index Warnings: Warning 3126 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 <in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on PRIMARY))) Specify at different levels, hint inside block has effect EXPLAIN SELECT /*+ SUBQUERY(@subq MATERIALIZATION) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq) SEMIJOIN() */ a FROM t1); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 NULL index a a 4 NULL 4 100.00 Using index 1 SIMPLE t1 NULL eq_ref PRIMARY PRIMARY 4 test.t2.a 1 100.00 Using index Warnings: Warning 3126 Hint SUBQUERY(@`subq` MATERIALIZATION) is ignored as conflicting/duplicated Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`subq`) */ `test`.`t2`.`a` AS `a` from `test`.`t1` join `test`.`t2` where (`test`.`t1`.`a` = `test`.`t2`.`a`) EXPLAIN SELECT /*+ SUBQUERY(@subq INTOEXISTS) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq) NO_SEMIJOIN() */ a FROM t1); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 NULL index NULL a 4 NULL 4 100.00 Using where; Using index 2 DEPENDENT SUBQUERY t1 NULL unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index Warnings: Warning 3126 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 <in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on PRIMARY))) EXPLAIN SELECT /*+ SEMIJOIN(@subq FIRSTMATCH) */ * FROM t2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq) SUBQUERY(@subq INTOEXISTS) */ a FROM t1); id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 NULL index NULL a 4 NULL 4 100.00 Using where; Using index 2 DEPENDENT SUBQUERY t1 NULL unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index Warnings: Warning 3126 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 <in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on PRIMARY))) drop table t1, t2, t3;