SQL索引选择性过低_区分度对查询影响

4次阅读

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

SQL 索引选择性过低_区分度对查询影响

索引选择性低,意味着该列中重复值多、唯一值少,比如性别、状态(启用 / 禁用)、是否删除等字段。这类索引在大多数查询中难以有效过滤数据,优化器往往直接放弃使用,转而走全表扫描。

为什么低选择性索引效果差?

数据库优化器判断是否走索引,核心依据之一是“预估返回行数”。如果某列只有 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) 避免回表
  • 物化视图或汇总表:对高频统计场景(如“查所有已关闭订单”),单独维护状态聚合表
text=ZqhQzanResources