问题定义
SQL 语句
SELECT * FROM TBL_XXX WHERE A = "abc" AND B IN (1, 2, 3);索引TBL_XXX 表上有 idx_a、idx_b 两个非唯一索引。
问题
由于 A、B 非联合索引,因此只会用到 idx_a;当 A 列筛选出的行数很大时,结果集的每一行都要做回表,去判断是否满足 B 列条件,从而造成查询超时。
解决方案
改进后 SQL 语句
SELECT * FROM TBL_XXX WHERE A = "abc" AND B = 1
UNION ALL
SELECT * FROM TBL_XXX WHERE A = "abc" AND B = 2
UNION ALL
SELECT * FROM TBL_XXX WHERE A = "abc" AND B = 3;原理剖析
通过 EXPLAIN 指令可以发现,三条 SELECT 语句的 Extra 列有的是 Using where、有的是 Using intersect,这是因为 MySQL 根据 B 条件不同的取值计算出了不同的扫描行数,选择了该条件下它所认为的最优方式。
Using intersect 能够对多个扫描结果取交集,这里相当于是对  B 列每个条件得到的结果集 与 A 列分别取了交集做了多次查询,再将最后得到的结果集取并集,从而无需再回表;即使 SQL 语句后面还有 C = "xyz" 的非索引列条件,也仅需在交集上做回表,大幅降低了回表次数。
Using intersect 条件
SQL 语句为多个索引的 AND 条件时,满足:
- 如果是二级索引,必须是等值查询,且覆盖其中所有索引列
- 如果是主键索引,可以是范围查询 - SELECT * FROM TBL_XXX WHERE primary_key < 10 AND key_col1 = 20;
参考
文章标题:Using intersect 多索引查询
文章作者:nek0peko
文章链接:https://nek0peko.com/index.php/archives/473/
商业转载请联系站长获得授权,非商业转载请注明本文出处及文章链接,未经站长允许不得对文章文字内容进行修改演绎。
本文采用创作共用保留署名-非商业-禁止演绎4.0国际许可证