索引选择性是数据库索引设计中常被忽略却至关重要的概念。它直接决定了索引能否有效加速查询,还是成为写入和存储的负担。本文不讨论索引的基础语法,而是聚焦于选择性本身:它如何定义、如何计算、如何影响查询效率,以及在实际建索引时如何利用它做出取舍。需要先说明边界:本文的结论基于常见的关系型数据库(如 MySQL、PostgreSQL)的 B+ 树索引模型,不适用于全文索引或空间索引;具体的数据分布和优化器行为可能因版本而异,但核心原则是通用的。
什么是索引选择性
索引选择性是指索引列中不同值的数量与表中总行数的比值,即 distinct 值个数 / 总行数。比值越接近 1,选择性越高,表示索引列能更精确地定位数据;比值越低,选择性越差,表示索引列存在大量重复值,查询时可能返回大量行。
例如,一个用户表有 100 万行,性别列只有 ‘男’ 和 ‘女’ 两个值,选择性为 0.000002,极低;而用户 ID 列有 100 万个不同值,选择性为 1,极高。显然,用性别列建索引很难加速查询,而用用户 ID 建索引则能快速定位。
选择性如何影响查询效率
查询优化器在选择执行计划时,会估算使用索引后需要扫描的行数(即“基数估计”)。选择性越高的索引,优化器预估的行数越少,越倾向于使用该索引。反之,选择性低的索引可能导致优化器放弃索引,转而进行全表扫描。
关键点在于:索引扫描本身有成本(读取索引页、回表等),如果选择性低,通过索引获取的行占比过高,优化器会认为全表扫描顺序 IO 更快。这种“索引失效”并非索引损坏,而是选择性不足导致优化器决策变化。
一个典型例子:在订单表的状态列(只有几个状态值)上建索引,查询“状态=’已完成’”可能返回 40% 的行,此时索引扫描加回表的代价远超全表扫描,优化器会直接扫表。
如何计算和评估选择性
计算单列选择性很简单:SELECT COUNT(DISTINCT col) / COUNT(*) FROM table;。对于复合索引,需要看组合列的 distinct 组合数除以总行数,通常用 COUNT(DISTINCT col1, col2) 估算。
实际工作中,不必精确计算,可以通过查询计划中的预估行数判断。执行 EXPLAIN 时,关注 rows 字段:如果预估扫描行数占总行数比例过高(如超过 20%),则说明选择性可能不足。另外,SHOW INDEX FROM table 中的 Cardinality 字段直接给出索引的基数(不同值个数),除以表行数即可得到选择性。
注意:Cardinality 是采样估算值,可能不完全准确,但足以用于初步判断。更精确的方法是用实际查询的慢日志验证。
提升索引选择性的实用策略
当发现索引选择性不足时,有几种常见策略:
- 使用复合索引:将选择性低的列与选择性高的列组合。例如,订单表按“状态 + 创建时间”建索引,状态区分度低但时间区分度高,组合后选择性大幅提升,且能覆盖常见查询。
- 前缀索引:对于长字符串列,如 URL 或文本,可以使用列的前缀作为索引。例如
INDEX (url(20)),但需要测试不同前缀长度的选择性,平衡索引大小和区分度。 - 调整查询条件:如果查询无法利用索引,可以考虑重写 SQL,例如增加过滤条件或使用覆盖索引(select 的列都包含在索引中,避免回表)。
- 考虑列的分布:如果某列数据分布极不均匀(例如 99% 是同一个值),即使选择性计算值不低,实际效果也可能很差,此时需要结合业务分布判断。
一个实践案例:在用户登录日志表中,按“用户 ID + 登录时间”建复合索引,比单独在“用户 ID”上建索引更有效,因为用户 ID 的选择性已经很高,但加上时间可以支持范围查询,并减少索引页的访问量。
常见误区和失败条件
误区一:选择性越高越好。实际上,选择性高的列往往重复值少,但如果你经常查询的列本身选择性低(如状态),强行加索引可能毫无帮助,反而增加写入开销。
误区二:忽略查询模式。索引选择性必须结合具体查询条件。一个复合索引可能选择性很高,但如果查询只用了第二列而未用第一列,索引可能完全失效(最左前缀原则)。
失败条件:当选择性过低(如低于 0.01)且数据量小时,优化器可能直接全表扫描;当索引列频繁更新时,维护索引的代价可能超过查询收益。
与查询计划、索引失效的关联
索引选择性是查询计划中优化器决策的核心依据之一。理解选择性有助于解释“为什么索引没被使用”这类问题。例如,在排查索引失效时,除了考虑函数操作、隐式转换等,还应检查选择性是否过低。相关的实战方法可参考站内文章:数据库索引失效的常见原因与排查方法,以及 如何分析SQL查询计划并优化索引设计。此外,理解 B+ 树结构有助于把握索引选择性的物理意义,参见 MySQL InnoDB存储引擎索引原理与B+树慢查询优化实战。
参考资料
本文参考了以下来源,它们提供了关于日志和可观测性中索引与查询优化的背景知识:
延伸阅读
