低选择性索引效果差,因其重复值多、唯一值少,导致优化器预估返回行数过高而弃用索引,转为全表扫描;常见于布尔型、枚举类、小范围取值及高null值字段。

索引选择性低,意味着该列中重复值多、唯一值少,比如性别、状态(启用/禁用)、是否删除等字段。这类索引在大多数查询中难以有效过滤数据,优化器往往直接放弃使用,转而走全表扫描。
为什么低选择性索引效果差?
数据库优化器判断是否走索引,核心依据之一是“预估返回行数”。如果某列只有2个值(如status IN ('0','1')),且数据均匀分布,那么走索引后仍需回表读取约50%的行——这比直接扫描聚簇索引(如InnoDB主键B+树)开销更大。此时索引不仅没提速,反而增加存储和维护成本。
哪些字段容易出现选择性过低?
- 布尔型字段(is_deleted、is_active)
- 枚举类字段(gender、order_status、pay_type)
- 固定取值范围小的字段(地区编码前两位、年份(若只存近3年))
- 大量NULL值的字段(NULL本身也属于一种“值”,会拉低选择性)
怎么判断一个索引是否值得建?
可用以下SQL粗略估算选择性:
SELECT COUNT(DISTINCT column_name) / COUNT(*) AS selectivity FROM table_name;
一般建议:选择性 > 0.1(即10%以上)才考虑单列索引;低于0.01(1%)基本不建议单独建索引。但也要结合查询模式——比如常与高选择性字段组合查询,可建联合索引并把低选择性字段放在后面。
低选择性字段还能优化查询吗?
-
组合索引中做后置字段:如
(user_id, status),利用user_id高选择性快速定位,status仅用于进一步过滤 - 分区裁剪替代索引:按时间/状态分区,查询时直接跳过无关分区
-
覆盖索引减少回表:即使status选择性低,若查询只涉及status+id+name,可建
(status, id, name)避免回表 - 物化视图或汇总表:对高频统计场景(如“查所有已关闭订单”),单独维护状态聚合表










