问题定义
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国际许可证
pumfsllmpvqidejsifnppijrwloywz