0
0
0

MySQL 联合索引:范围定位与 ICP 过滤的判断

2026-10-27
2026-10-27
文章摘要
|

一、核心区别

类型

作用

等值定位

利用索引快速定位到指定值

范围定位

利用索引有序性,缩小需要扫描的索引范围

ICP 过滤

扫描索引时提前过滤不符合条件的记录,减少回表

核心区别:范围定位减少索引扫描量,ICP 减少回表量。

二、联合索引的排序规则

假设存在联合索引:

INDEX idx_user_status_age (user_id, status, age)

索引数据:

user_id    status    age
------------------------
zhang01      1       18
zhang01      1       20
zhang01      2       19
zhang01      2       21
zhang02      1       18
zhang02      1       20
zhang02      2       19
zhang02      2       21

联合索引的排序规则:

  1. 首先按照 user_id 排序。

  2. user_id 相同时,再按照 status 排序。

  3. user_id 和 status 都相同时,再按照 age 排序。

关键:后面的字段只有在前面的字段值确定时,才能形成连续的有序范围。

三、如何判断范围定位还是 ICP?

示例一:等值 + 范围,可以继续定位

SELECT *
FROM user
WHERE user_id = 'zhang01'
  AND status > 3;

条件

判断

user_id = 'zhang01'

等值定位

status > 3

范围定位

原因:

user_id 已经固定为 zhang01,因此这一组里的 status 是有序的。

zhang01 → status: 1, 2, 3, 4, 5, 6
                            ↑
                       从 >3 开始扫描

MySQL 可以直接定位到 status > 3 的范围,不需要扫描前面不符合条件的索引记录。

示例二:LIKE 范围 + 其他条件,通常使用 ICP

SELECT *
FROM user
WHERE user_id LIKE 'zhang%'
  AND status > 3;

条件

判断

user_id LIKE 'zhang%'

范围定位

status > 3

ICP 过滤候选条件

原因:

LIKE 'zhang%' 会匹配多个不同的 user_id。

user_id    status
-----------------
zhang01      1
zhang01      5
zhang02      2
zhang02      6
zhang03      3
zhang03      7

虽然同一个 user_id 下面的 status 是有序的,但多个 user_id 放在一起:

status: 1, 5, 2, 6, 3, 7

status 在整个扫描范围内不是连续有序的,因此通常无法继续缩小索引扫描范围。

但可以在扫描索引时判断 status > 3,通过 ICP 提前过滤,减少回表。

注意:不是 status 没有排序,而是它只在相同 user_id 的分组内部有序。

示例三:范围条件后面的字段,通常不能继续定位

SELECT *
FROM user
WHERE user_id = 'zhang01'
  AND status > 3
  AND age = 20;

条件

判断

user_id = 'zhang01'

等值定位

status > 3

范围定位

age = 20

ICP 过滤候选条件

原因:

虽然 user_id 已经固定,但是 status > 3 包含多个不同的 status 值。

user_id    status    age
------------------------
zhang01      4       18
zhang01      4       20
zhang01      5       19
zhang01      5       20
zhang01      6       21

age 只在相同 status 的分组中有序。

把 status > 3 的记录放在一起,age 不是整体有序的,因此通常不能继续缩小连续扫描范围,只能作为 ICP 过滤条件。

示例四:前面都是等值,最后一列可以范围定位

SELECT *
FROM user
WHERE user_id = 'zhang01'
  AND status = 4
  AND age > 20;

条件

判断

user_id = 'zhang01'

等值定位

status = 4

等值定位

age > 20

范围定位

原因:

user_id 和 status 都已经固定,age 在这个分组内连续有序,因此可以直接进行范围定位。

四、判断口诀

针对普通联合索引的连续范围扫描:

前面等值,可以继续定位;遇到范围,后面通常转为索引过滤。

判断步骤:

  1. 按照联合索引的字段顺序分析,而不是 WHERE 的书写顺序。

  2. 前面的字段是等值条件,后面的字段可以继续参与定位。

  3. 遇到 >、<、BETWEEN、前缀 LIKE 等范围条件时,要判断后面的字段能否继续缩小扫描区间;通常不能。

  4. 后面的字段如果包含在索引中,可以用于 ICP 等索引层过滤;如果不在索引中,通常需要回表后过滤。

注意:这是常见连续范围扫描的判断方法,不是绝对规则。例如 IN 可以形成多个索引区间,BETWEEN 的边界也可能利用后续索引列。是否真正启用 ICP,要看 EXPLAIN 的 Using index condition。

最终记住:能利用索引有序性缩小扫描范围的是定位;不能缩小范围、但能在索引扫描过程中提前筛选记录的,才是 ICP 过滤的典型场景。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或者给予支持!

评论