MySQL 8.0.13+才支持Partial Index(部分索引),语法为CREATE INDEX ... WHERE,低版本直接报错;适用于状态分布极不均匀且仅高频查询少数值的场景,需严格匹配字面量并查information_schema确认PARTIAL标识。

MySQL 8.0+ 才支持 Partial Index(部分索引)
MySQL 直到 8.0.13 版本才正式引入 CREATE INDEX ... WHERE 语法,也就是部分索引。如果你用的是 5.7 或更早版本,这条语句会直接报错:ERROR 1064 (42000): You have an error in your SQL syntax。别急着改代码,先确认版本:
SELECT VERSION();
常见误区是以为加了 WHERE 就能过滤索引内容——但低版本 MySQL 根本不识别该语法,也不会静默忽略,而是明确拒绝执行。
状态字段适合建部分索引的典型场景
不是所有状态字段都值得上 Partial Index。它真正起效的前提是:状态值分布极不均匀,且你只高频查询其中少数几个值(比如 'active'、'pending'),而其他值(如 'archived'、'deleted')几乎不参与查询或占比极大但无需加速。
- ✅ 合适:订单表中
status字段,95% 是'completed',但业务只查'processing'和'failed'的实时监控 - ❌ 不合适:用户表
status只有'normal'/'locked'两种,各占 50%,建部分索引反而浪费空间且无法覆盖全部查询 - ⚠️ 风险:若后续业务开始查
WHERE status IN ('active', 'inactive', 'pending'),而你只建了WHERE status = 'active'的部分索引,那后两个值仍走全表扫描
正确创建 Partial Index 的写法与陷阱
语法必须严格遵循 WHERE 后接确定布尔表达式,不能含函数、子查询或参数化变量。以下为有效示例:
CREATE INDEX idx_order_status_active ON orders(status) WHERE status = 'active';
这些写法会失败:
-
WHERE status IN ('active', 'pending')—— MySQL 8.0.13–8.0.20 不支持多值IN,需拆成多个单值索引或升级到 8.0.21+ -
WHERE UPPER(status) = 'ACTIVE'—— 不允许函数包装列 -
WHERE status = @var—— 不接受用户变量 -
WHERE status IS NOT NULL—— 虽语法合法,但对统计查询无实际加速意义(B+ 树本身就不存 NULL)
另外注意:Partial Index 仍受普通索引限制——比如不能在 TEXT 列上直接建(需前缀长度),也不能在未显式声明 NOT NULL 的字段上依赖非空假设。
验证是否命中部分索引比想象中难
EXPLAIN 显示 key 列有索引名,并不代表一定用了该部分索引。MySQL 优化器可能因统计信息不准、成本估算偏差或隐式类型转换而跳过它。关键检查点:
- 确保
WHERE条件字面量与索引定义中的完全一致(大小写、引号、空格);'Active'≠'active' - 执行
ANALYZE TABLE orders;更新统计信息,否则优化器可能误判部分索引“选择性太低”而弃用 - 用
SELECT * FROM information_schema.STATISTICS WHERE TABLE_NAME = 'orders' AND INDEX_NAME = 'idx_order_status_active';确认INDEX_COMMENT字段是否包含PARTIAL标识 - 真实压测时观察
Handler_read_next和Handler_read_rnd_next的差值——部分索引应显著降低后者
最隐蔽的问题是:部分索引不会出现在 SHOW INDEX 的 Comment 列里,必须查 information_schema.STATISTICS 才能确认它是不是 partial 类型。漏掉这步,很容易误以为建的是普通索引。


















