在数据库优化中,索引选择性是一个容易被忽视但非常关键的指标。索引选择性指的是某个索引列中不重复值的数量与表中总记录数的比例,比例越接近1说明区分度越高,越接近0说明区分度越低。当SQL索引选择性过低时,对查询性能和数据库整体效率都会带来明显的负面作用。
什么是索引选择性与区分度
索引选择性(Index Selectivity)可以用下面这个公式衡量:
-- 计算某个字段的选择性 SELECT COUNT(DISTINCT column_name) / COUNT(*) AS selectivity FROM table_name;
如果结果接近1,说明该列值非常分散,区分度高;如果结果很小,比如0.01,就说明大量行拥有相同值,区分度低。像状态字段、性别字段这类取值很少的列,往往选择性很低。
选择性过低对查询的影响
优化器可能放弃使用索引
当索引选择性过低时,通过索引扫描往往要回表访问绝大多数数据块。数据库优化器在评估执行计划后,通常认为直接全表扫描成本更低,于是忽略该索引。此时你建的索引成了摆设。
增加写操作与存储负担
即使查询用不上,低区分度索引在INSERT、UPDATE、DELETE时仍要维护。它占用磁盘空间,还拖慢写入速度。
引发大量随机IO
若强制使用低选择性索引,数据库会先扫索引再频繁回表,产生很多随机IO,查询反而比顺序全表扫描更慢。
如何避免低选择性索引问题
- 只为区分度高的列建单列索引
- 对低区分度列可采用联合索引,把它放在后面
- 对状态类字段可用覆盖索引减少回表
- 定期分析表,删除从未被使用的索引
示例:性别字段建索引的代价
以下语句在性别字段上建索引,但性别只有男、女,选择性极低:
-- 不建议对低区分度字段单独建索引 CREATE INDEX idx_gender ON user(gender); -- 查询时优化器通常选择全表扫描 EXPLAIN SELECT * FROM user WHERE gender = '男';
执行计划一般显示type为ALL,即全表扫描,说明索引未被采用。
总结
SQL索引选择性过低会削弱索引应有的加速作用,甚至带来额外负担。我们在设计索引时,应优先关注列的区分度,结合业务查询模式建立真正有效的索引,而不是盲目添加。