在做数据库开发时,我们常常遇到这样的现象:已经给关联查询的字段建立了单列索引,但执行起来仍然很慢。其中一个容易被忽略的原因是关联字段的选择性过低,导致索引无法有效过滤数据。
什么是索引选择性
索引选择性(Selectivity)是指字段中不同值的数量与总记录数的比例。比例越接近1,说明字段区分度越高;越接近0,说明重复值越多。例如用gender字段关联,可能只有男和女两个值,选择性极低。
如何计算选择性
可以通过下面SQL估算关联字段的选择性:
-- 计算 user_id 字段的选择性 SELECT COUNT(DISTINCT user_id) / COUNT(*) AS selectivity FROM orders;
如果结果小于0.1,通常认为选择性较低,单列索引效果有限。
低选择性导致慢查询的原因
当关联字段选择性过低时,即使使用了单列索引,数据库仍要处理大量重复键值的匹配。以A表关联B表为例:
- 索引快速定位到某个性别值,但对应成千上万行;
- 每一行都要去另一张表回表查找或产生笛卡尔式膨胀;
- 临时结果集过大,排序或IO开销急剧上升。
查看执行计划
使用EXPLAIN观察是否真的用到索引,以及扫描行数:
EXPLAIN SELECT a.id, b.name FROM users a JOIN profiles b ON a.gender = b.gender;
若rows列显示扫描了几乎全表,且type为index或ALL,就说明选择性低让索引失去意义。
优化思路与示例
1. 组合索引提升区分度
将低选择性字段与高选择性字段组合:
-- 建立组合索引 CREATE INDEX idx_user_region_id ON users (gender, user_id);
2. 改写关联逻辑
先过滤再关联,减少参与JOIN的数据量:
SELECT a.id, b.name FROM (SELECT id, gender FROM users WHERE status = 1) a JOIN profiles b ON a.gender = b.gender;
3. 用唯一或近唯一字段关联
业务允许时,尽量使用主键或订单号等选择性高的字段做关联条件。
| 关联字段类型 | 选择性 | 单索引效果 |
|---|---|---|
| 主键ID | 极高 | 很好 |
| 手机号 | 高 | 较好 |
| 性别 | 极低 | 很差 |
因此,当SQL关联查询在单索引下依然慢,应先检查关联字段的选择性是否过低,再决定是调整索引还是改写SQL。