高基数字段是否建索引关键看选择性(满足条件行数/总行数),理想值趋近0;一般<5%适合索引,>20%优化器常弃用;需结合查询模式、统计信息准确性和分布倾斜度综合判断。
高基数字段是否值得建索引,不能只看“唯一值多”,关键要看选择性(Selectivity)——即查询时能过滤掉多少数据。选择性越高,索引效率越明显;反之,即使字段唯一值上百万,若常用查询条件匹配大量行,索引可能被优化器弃用。
选择性 = 满足条件的行数 / 表总行数(理想值趋近于 0,越小越好)。例如:用户表 1000 万行,user_id 是主键,查单个 ID 的选择性是 1/10000000 ≈ 0.0000001;而 status 字段有 3 个值且分布均匀,查 status = 'active' 的选择性约为 0.33。
SELECT COUNT(*) FILTER (WHERE status = 'pending') * 1.0 / COUNT(*) FROM users;(PostgreSQL)或用子查询兼容 MySQL一个字段整体唯一值很多(如订单号、设备 ID),但业务查询常带时间范围或状态前缀,真实过滤效果取决于组合条件下的有效选择性。
order_no 全局唯一,但查询 WHERE order_no LIKE '202510%' 可能命中上万条——此时单独对 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)ALTER TABLE t ALTER COLUMN c SET STATISTICS 1000)WHERE 中对字段做函数操作(如 YEAR(created_at) = 2025),这会让统计失效,也使索引无法使用仅靠 COUNT(DISTINCT) 不够——它不反映分布倾斜。比如用户地区字段有 200 个唯一值,但 80% 数据集中在 3 个省份,查其余 197 个值的选择性极好,查那 3 个却很差。
pg_stats 表、MySQL 的 information_schema.COLUMN_STAT
ISTICS)了解值分布ndv(Number of Distinct Values)和常见值频次,识别“长尾”还是“尖峰”分布