低选择性索引会拖慢查询,因其重复值过多导致优化器放弃使用而改用全表扫描;索引选择性低于0.05时通常无效,且会增加写入开销和内存占用,应优先考虑覆盖索引、分区或汇总表等替代方案。
为什么低选择性索引反而拖慢查询
当 WHERE 条件字段的重复值过多(比如 status 只有 ‘0’/’1’,或 gender 只有 ‘M’/’F’),MySQL 很可能直接放弃走索引,改用全表扫描——因为走索引要回表多次,成本比扫一遍还高。
典型表现:EXPLAIN 中 type 是 ALL 或 index,key 为空,rows 接近表总行数。
- 索引选择性 =
COUNT(DISTINCT column) / COUNT(*);低于 0.05 通常视为低选择性 - 即使加了索引,优化器也可能忽略它——这不是 bug,是成本估算结果
-
FORCE INDEX强制走索引往往更慢,别试
用覆盖索引绕过回表开销
如果查询只涉及少量字段,且这些字段都在索引里,MySQL 就不用回主键查找数据行。这对低选择性字段特别有效。
例如:查询 SELECT id, status FROM orders WHERE status = 1,可建联合索引:ALTER TABLE orders ADD INDEX idx_status_id (status, id)。
- 顺序很重要:低选择性字段放前面(
status),高选择性字段放后面(id) - 避免
SELECT *,只查真正需要的列 - 覆盖索引对
ORDER BY和LIMIT也友好,能避免 filesort
用分区或物化视图替代单字段索引
对固定取值、高频过滤但低选择性的字段(如 tenant_id、region),单列索引意义不大,可考虑按该字段做范围/列表分区。