config root man

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
Upload File :
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;

Man Man