Semi-join FirstMatch 子查询优化策略

本篇为子查询优化系列第三篇,翻译自 MariaDB 博客:https://mariadb.com/kb/en/firstmatch-strategy/,建议先看 MySQL子查询优化 和 Semi-join Materialization 子查询优化策略

实现思路

FirstMatch 是子查询 semijoin 优化的一种实现策略。下面通过一个示例来说明其原理,要查找欧洲有100万人口以上城市的国家:

select * from Country 
where Country.code IN (select City.Country 
                       from City 
                       where City.Population > 1*1000*1000)
      and Country.continent='Europe'

常规 join 的过程是下图这样的:

由于 Germany 有两个大城市(在该图中),所以联接结果中会有2个 Germany。 这是不正确的,SELECT ... FROM Country不应该得到两个相同的国家记录。FirstMatch 就是去重的一种策略,一旦找到第一个匹配项,就可以回到驱动表取下一行数据与被驱动表进行关联:

如上图,执行过程为:

  1. 驱动表是 country 表,从 country 表中取出一行 R;
  2. 从R 中取出 code 字段,到被驱动表 city 表中进行查找,只要找到第一个匹配的记录,就不再往下继续查找;
  3. 重复 1、2 ,直到结束。

执行成本

使用 Semi-join FirstMatch 优化策略的执行计划如下:

select * from Country  where Country.code IN (select City.Country from City \
where City.Population > 1*1000*1000) and Country.continent='Europe';
+----+-------------+---------+-----------+--------------------+------+----------------------------------+
| id | select_type | table   | key       | ref                | rows | Extra                            |
+----+-------------+---------+-----------+--------------------+------+----------------------------------+
|  1 | PRIMARY     | Country | continent | const              |   60 | Using index condition            |
|  1 | PRIMARY     | City    | Country   | world.Country.Code |   18 | Using where; FirstMatch(Country) |
+----+-------------+---------+-----------+--------------------+------+----------------------------------+

Extra 列中会有 FirstMatch(Country) 标识,总扫描行数为 60+60*18.

小结

  1. 在执行计划中,FirstMatch 显示在 Extra 信息中 FirstMatch(驱动表);
  2. 通过参数 optimizer_switch 中的 semijoin=on 和 firstmatch=on 开启 Semi-join FirstMatch,默认就是开启的。

你可能感兴趣的:(Semi-join FirstMatch 子查询优化策略)