索引选择性是判断建索引与否的核心依据,计算公式为去重值数量除以总行数,取值0~1;越高越适合建索引,但需结合查询模式、覆盖需求、JOIN频率等综合决策。

索引选择性是 MySQL 优化中判断“该不该建索引”“该建什么索引”的核心依据,面试官常通过它考察你对索引底层逻辑和实际调优能力的理解,不只考定义,更看重你怎么用它做决策。
什么是选择性?怎么算?
选择性(Selectivity)= 某列去重值数量 / 该列总行数,取值范围在 0 到 1 之间。越接近 1,说明该列值越分散,区分度越高;越接近 0,说明重复值越多,区分度越低。
例如:用户表的 user_id 是主键,10 万行数据就有 10 万个不同值,选择性 = 100000/100000 = 1;而 gender 只有 'M'/'F'/'O' 三种值,选择性 ≈ 3/100000 = 0.00003。
MySQL 中可快速估算:
SELECT COUNT(DISTINCT column_name) / COUNT(*) AS selectivity FROM table_name;
为什么高选择性更适合建索引?
因为 B+ 树索引靠“快速过滤”提升查询效率。高选择性列能用更少的索引层级筛掉大量无关行,减少回表或扫描开销。
- 查 email(唯一性高)→ 索引定位到 1 行,几乎不回表
- 查 status(如 90% 是 'active')→ 索引可能命中上万行,优化器大概率放弃索引,直接全表扫描
- 复合索引中,把选择性高的列放在前面,能更早剪枝,提升整体效率
选择性不是唯一标准,还要看查询模式
即使某列选择性低,只要满足以下条件,仍值得建索引:
- 经常出现在 WHERE + 等值查询 中,且结果集固定很小(比如 status = 'deleted' 只有几百行)
- 用于 ORDER BY 或 GROUP BY,避免文件排序(filesort)
- 作为 覆盖索引的一部分,避免回表(例如联合索引 (status, create_time, id),查询这三列时无需访问主键表)
- 被高频 JOIN 使用(如外键列),即使重复值多,但连接效率提升明显
面试常问陷阱题怎么答?
➤ “性别字段选择性极低,为什么有时还要加索引?” 答:要看实际查询场景。比如后台要统计“所有女性用户”,且表很大但女性只占 5%,加上索引后可能走 index range scan,比全表扫描快;或者它在联合索引里承担排序/覆盖角色,此时它的低选择性不影响整体价值。
➤ “是不是选择性 > 0.2 就该建索引?” 答:没有固定阈值。0.01 的列在某些业务下也有效,0.8 的列如果从不被 WHERE 过滤,建了也是浪费。关键看 执行计划是否真用、查询频次、维护成本(写入变慢、磁盘占用)是否可接受。










