知识卡片
一个查询只能用上一个范围条件,后面的索引列会失效
内容
EXPLAIN的type列用同一个词”range”来描述两种本质不同的访问方式:真正的
范围查询(如actor_id > 45)和多值等值查询(如actor_id IN(1,4,99)),
但这两者对索引的利用效率并不相同——对于真正的范围条件,MySQL无法再
使用该索引里排在这一列之后的其他列,而”多个等值条件”(IN列表)没有这个
限制。这带来一个实际约束:如果一个查询同时对两个字段做范围过滤(比如
last_online > ...且age BETWEEN 18 AND 25),MySQL只能选择用其中一个
字段的索引,另一个字段的过滤条件无法再借助索引、只能在已筛出的行里逐条
判断。书中给出一个具体的规避技巧:把其中一个”范围”语义的字段转换成一个
预先计算好的”等值”字段——例如不直接在索引里判断last_online这个连续
时间范围,而是维护一个由定时任务更新的active布尔列(登录即置1,连续
7天未登录置0),这样查询条件就从”两个范围”变成”一个等值(active=1)+一个
范围(age)”,从而可以把active放进多列索引的前列,配合age一起被
索引利用。这个技巧的代价是精度打了折扣(active不是分钟级实时的),但
换来的是查询能重新用上索引;如果业务确实需要精确的last_online,可以
把它保留在WHERE子句里过滤、但不进索引,用”索引外的精确过滤+索引内的
粗粒度快速定位”分工协作。这说明索引设计遇到”天生无法被索引同时满足”的
多条件组合时,思路不必局限在”加更多索引”,也可以反过来改造数据/schema,
把某个查询维度从”范围”降级为”等值”,让它重新落进索引能覆盖的模式里。
参考来源
- 位置:《高性能MySQL:第3版》第5章"创建高性能的索引"5.4.2节"避免多个
范围条件"(源文件:_epub-src/OEBPS/Text/part0012.xhtml)
- 结论依据:原文明确"对于范围条件查询,MySQL无法再使用范围列后面的
其他索引列了,但是对于'多个等值条件查询'则没有这个限制……我们需要
事先计算好一个active列……这个方法可以让MySQL使用(active,sex,
country,age)索引",直接说明范围条件对索引列利用的限制及预计算
等值列的规避技巧。
- 原始内容:对于范围条件查询,MySQL无法再使用范围列后面的其他索引列
了,但是对于"多个等值条件查询"则没有这个限制……我们需要事先计算好
一个active列,这个字段由定时任务来维护。