1. 背景介绍
什么是semi-join?
所谓的semi-join是指semi-join子查询。 当一张表在另一张表找到匹配的记录之后,半连接(semi-jion)返回第一张表中的记录。与条件连接相反,即使在右节点中找到几条匹配的记录,左节点 的表也只会返回一条记录。另外,右节点的表一条记录也不会返回。半连接通常使用IN 或 EXISTS 作为连接条件。 该子查询具有如下结构:
SELECT ... FROM outer_tables WHERE expr IN (SELECT ... FROM inner_tables ...) AND ...
即在where条件的“IN”中的那个子查询。
这种查询的特点是我们只关心outer_table中与semi-join相匹配的记录。
换句话说,最后的结果集是在outer_tables中的,而semi-join的作用只是对outer_tables中的记录进行筛选。这也是我们进行 semi-join优化的基础,即我们只需要从semi-join中获取到最少量的足以对outer_tables记录进行筛选的信息就足够了。
所谓的最少量,体现到优化策略上就是如何去重。
以如下语句为例:
select * from Country where Country.Code in (select City.country from City where City.Population>1*1000*1000);
当中的semi-join: “
select City.country from City where City.Population>1*1000*1000
” 可能返回的结果集如下: China(Beijin), China(Shanghai), France(Paris)...
我们可以看到这里有2个China,分别来至2条城市记录Beijin和Shanghai, 但实际上我们只需要1个China就足够对outer_table
2. Mysql支持的Semi-join策略
Mysql支持的semi-join策略主要有5个,它们分别为:
1. DuplicateWeedout: 使用临时表对semi-join产生的结果集去重。
![](https://i-blog.csdnimg.cn/blog_migrate/3c74224beec81d8e4783a35880de2e15.png)
对应的匹配条件为:
![](https://i-blog.csdnimg.cn/blog_migrate/35b5168dddf888f056ee6b2ecc2306be.png)
2. FirstMatch: 只选用内部表的第1条与外表匹配的记录。
![](https://i-blog.csdnimg.cn/blog_migrate/30c65c5c7f380e8a623d29fdf3e3de20.png)
对应的匹配条件为:
![](https://i-blog.csdnimg.cn/blog_migrate/3c612d9ebf4d4acf4c80b693d610dfc5.png)
3. LooseScan: 把inner-table数据基于索引进行分组,取每组第一条数据进行匹配。
![](https://i-blog.csdnimg.cn/blog_migrate/31e2d53f770d00ddacfbc1e943ca25f1.jpeg)
对应的匹配条件为:
![](https://i-blog.csdnimg.cn/blog_migrate/be282d066f3b03686ace1eae62fd9dd8.jpeg)
4. Materializelookup: 将inner-table去重固化成临时表,遍历outer-table,然后在固化表上去寻找匹配。
对应的匹配条件:
![](https://i-blog.csdnimg.cn/blog_migrate/ab50d4c13d78ab8919b8c09670977841.png)
5. MaterializeScan: 将inner-table去重固化成临时表,遍历固化表,然后在outer-table上寻找匹配。
![](https://i-blog.csdnimg.cn/blog_migrate/1a86f0dac3adc519dc5bb3a4c4c14041.png)
对应的条件:
![](https://i-blog.csdnimg.cn/blog_migrate/d6ca36fa29640419d20d33a444605566.png)
optimizer_switch
system variable. The
semijoin
flag controls whether semi-joins are used. If it is set to
on
, the
firstmatch
,
loosescan
, and
materialization
flags enable finer control over the permitted semi-join strategies. These flags are
on
by default.
The use of semi-join strategies is indicated in EXPLAIN
output as follows:
-
Semi-joined tables show up in the outer select.
EXPLAIN EXTENDED
plusSHOW WARNINGS
shows the rewritten query, which displays the semi-join structure. From this you can get an idea about which tables were pulled out of the semi-join. If a subquery was converted to a semi-join, you will see that the subquery predicate is gone and its tables andWHERE
clause were merged into the outer query join list andWHERE
clause. -
Temporary table use for Duplicate Weedout is indicated by
Start temporary
andEnd temporary
in theExtra
column. Tables that were not pulled out and are in the range ofEXPLAIN
output rows covered byStart temporary
andEnd temporary
will have theirrowid
in the temporary table. -
FirstMatch(
in thetbl_name
)Extra
column indicates join shortcutting. -
LooseScan(
in them
..n
)Extra
column indicates use of the LooseScan strategy.m
andn
are key part numbers.
-
As of MySQL 5.6.7, temporary table use for materialization is indicated by rows with a
select_type
value ofMATERIALIZED
and rows with atable
value of<subquery
.N
>Before MySQL 5.6.7, temporary table use for materialization is indicated in the
Extra
column byMaterialize
if a single table is used, or byStart materialize
andEnd materialize
if multiple tables are used. IfScan
is present, no temporary table index is used for table reads. Otherwise, an index lookup is used.
mysql> SELECT @@optimizer_switch\G *************************** 1. row *************************** @@optimizer_switch: index_merge=on,index_merge_union=on, index_merge_sort_union=on, index_merge_intersection=on, engine_condition_pushdown=on, index_condition_pushdown=on, mrr=on,mrr_cost_based=on, block_nested_loop=on,batched_key_access=off, materialization=on,semijoin=on,loosescan=on, firstmatch=on, subquery_materialization_cost_based=on, use_index_extensions=on