高基数字段是否建索引关键看选择性(满足条件行数/总行数),理想值趋近0;一般<5%适合索引,>20%优化器常弃用;需结合查询模式、统计信息准确性和分布倾斜度综合判断。

高基数字段是否值得建索引,不能只看“唯一值多”,关键要看选择性(Selectivity)——即查询时能过滤掉多少数据。选择性越高,索引效率越明显;反之,即使字段唯一值上百万,若常用查询条件匹配大量行,索引可能被优化器弃用。
什么是选择性?怎么算?
选择性 = 满足条件的行数 / 表总行数(理想值趋近于 0,越小越好)。例如:用户表 1000 万行,user_id 是主键,查单个 ID 的选择性是 1/10000000 ≈ 0.0000001;而 status 字段有 3 个值且分布均匀,查 status = 'active' 的选择性约为 0.33。
- 一般认为选择性 才较适合走索引
- 超过 0.2(20%)时,全表扫描往往更快,优化器大概率忽略该索引
- 计算示例:
SELECT COUNT(*) FILTER (WHERE status = 'pending') * 1.0 / COUNT(*) FROM users;(PostgreSQL)或用子查询兼容 MySQL
别只看全局基数,要看实际查询模式
一个字段整体唯一值很多(如订单号、设备 ID),但业务查询常带时间范围或状态前缀,真实过滤效果取决于组合条件下的有效选择性。
- 比如
order_no全局唯一,但查询WHERE order_no LIKE '202410%'可能命中上万条——此时单独对order_no建索引无意义 - 更优做法:把高频过滤字段(如
created_at)放在联合索引左侧,再加order_no,让索引能快速定位时间窗口内的数据 - 用
EXPLAIN ANALYZE看执行计划中Rows Removed by Filter占比,比理论值更真实
统计信息要准,否则评估会失真
优化器依赖表和列的统计信息估算选择性。如果 ANALYZE(PostgreSQL)或 UPDATE STATISTICS(SQL Server)长期未执行,或采样率过低,可能导致误判。
- 检查统计信息新鲜度:
pg_stat_all_tables.last_analyze(PG);sys.dm_db_stats_properties(SQL Server) - 对高基数字段,建议提高采样率(如 PG 中
ALTER TABLE t ALTER COLUMN c SET STATISTICS 1000) - 避免在
WHERE中对字段做函数操作(如YEAR(created_at) = 2024),这会让统计失效,也使索引无法使用
用直方图+NDV交叉验证更可靠
仅靠 COUNT(DISTINCT) 不够——它不反映分布倾斜。比如用户地区字段有 200 个唯一值,但 80% 数据集中在 3 个省份,查其余 197 个值的选择性极好,查那 3 个却很差。
- 查看列直方图(PostgreSQL 的
pg_stats表、MySQL 的information_schema.COLUMN_STATISTICS)了解值分布 - 结合
ndv(Number of Distinct Values)和常见值频次,识别“长尾”还是“尖峰”分布 - 对倾斜字段,可考虑分区 + 局部索引,或为高频值建覆盖索引,低频值走默认路径










