索引选择性等于字段不同值个数除以总行数,范围0~1,越接近1越适合建索引;可用COUNT(DISTINCT)/COUNT(*)计算,多字段可并行查询;≥0.95宜建单列索引,<0.01通常无效;复合索引需统计组合唯一值,高选择性字段应前置;Cardinality估算值可辅助判断,ANALYZE TABLE可更新统计。

索引选择性(也叫索引区分度)就是看一个字段“有多好分辨”。它等于这个字段中不同值的个数,除以表的总行数。结果在 0 到 1 之间,越接近 1,说明这个字段越适合单独建索引。
怎么用 SQL 算选择性
最直接的方法是执行一条统计查询:
- MySQL / PostgreSQL / SQL Server(带小数精度):
SELECT COUNT(DISTINCT column_name) * 1.0 / COUNT(*) AS selectivity FROM table_name; - SQLite(需显式转浮点):
SELECT CAST(COUNT(DISTINCT column_name) AS REAL) / COUNT(*) AS selectivity FROM table_name; - 想快速对比多个字段?可以一次查几个:
SELECT
COUNT(DISTINCT email) * 1.0 / COUNT(*) AS email_sel,
COUNT(DISTINCT gender) * 1.0 / COUNT(*) AS gender_sel
FROM users;
怎么看算出来的数合不合适
数值本身要结合业务场景判断,但有几条经验参考:
- ≥ 0.95:像主键、手机号、邮箱这类几乎唯一的字段,建单列索引效果很好
- 0.1 ~ 0.95:比如创建时间(按天)、地区编码、分类 ID,可考虑建索引,尤其当查询频率高或常用于 WHERE + ORDER BY 时
- < 0.01:如性别、是否删除(is_deleted)、状态码(status=0/1/2),单独建索引通常无效,优化器大概率会忽略,还增加写入开销
复合索引的选择性怎么估
联合字段的区分能力不能简单加总,得看组合后有多少唯一组合值:
- 基础写法(兼容多数数据库):
SELECT COUNT(DISTINCT CONCAT(col_a, '-', col_b)) * 1.0 / COUNT(*) FROM table_name; - 更严谨(避免分隔符干扰):
SELECT COUNT(DISTINCT col_a, col_b) * 1.0 / COUNT(*) FROM table_name;(MySQL 8.0+、PostgreSQL 支持) - 注意顺序:联合索引中,高选择性字段放前面,才能更好利用索引做范围扫描或跳过排序
别只信 COUNT(DISTINCT),也看看 Cardinality
MySQL 的 SHOW INDEX FROM table_name 会返回 Cardinality 字段,这是优化器对“该索引列唯一值数量”的估算值。虽然不是实时精确值,但能快速辅助判断:
- Cardinality 接近表总行数 → 该列很可能高选择性
- Cardinality 很小(比如只有几十或几百)→ 即使你没算过,也能怀疑它不适合单列索引
- 执行 ANALYZE TABLE table_name 可更新 Cardinality 统计,让估算更准










