mysql索引选择性与查询效率的关系

来源:这里教程网 时间:2026-02-28 20:40:13 作者:

索引选择性低会导致全表扫描

WHERE
条件列的选择性很低(比如性别字段只有
'男'
/
'女'
两种值),MySQL 优化器很可能放弃使用该索引,直接走全表扫描。因为回表或扫描索引本身开销可能比遍历整张表还大。

选择性 =
COUNT(DISTINCT column) / COUNT(*)
,越接近 1 越好(如用户邮箱)
低于 0.05~0.1 时,B+ 树索引通常失效(具体阈值受数据量、行大小、存储引擎影响)
EXPLAIN
查看
type
字段:若为
ALL
index
,说明没走有效索引

联合索引的最左前缀原则直接影响选择性判断

MySQL 只能利用联合索引的连续前缀部分。即使

(a, b, c)
a
选择性差,但
(a, b)
组合选择性高,查询
WHERE a = ? AND b = ?
仍可高效命中索引。

避免把低选择性字段放在联合索引最左侧(如
(status, user_id)
status
只有 3 个值)
高频等值查询字段优先靠左;范围查询(
>
,
BETWEEN
)字段必须放最右,否则右侧字段无法被索引使用
SHOW INDEX FROM table_name
确认索引定义顺序,别只看
CREATE INDEX
语句写法

NULL 值会破坏索引选择性统计准确性

MySQL 的

ANALYZE TABLE
在统计列基数(
Cardinality
)时,对含大量
NULL
的列可能严重低估实际区分度,导致优化器误判索引价值。

执行
SELECT COUNT(*), COUNT(column), COUNT(DISTINCT column) FROM table
对比真实选择性
若列允许
NULL
且占比高,考虑改用默认值(如
'unknown'
)替代,或在查询中显式排除:
WHERE column IS NOT NULL AND column = ?
innodb_stats_persistent = ON
+ 定期
ANALYZE TABLE
可缓解统计偏差,但无法根治
NULL
干扰

覆盖索引能绕过选择性瓶颈提升效率

即使筛选字段选择性低,只要查询所需所有字段都在索引中(即覆盖索引),MySQL 就无需回表,此时哪怕走

index
类型扫描,性能也远好于全表扫描。

例如表有
(status, create_time, id)
联合索引,查询
SELECT id FROM t WHERE status = 'draft'
就是覆盖扫描
注意
SELECT *
几乎不可能被覆盖,务必明确列出需要的字段
EXPLAIN
检查
Extra
列是否含
Using index
,这是覆盖索引生效的关键标志
EXPLAIN SELECT id, create_time FROM orders WHERE status = 'shipped';
索引选择性不是独立指标,它和查询模式、字段顺序、NULL 分布、是否覆盖紧密耦合。单独优化某列的选择性没意义,得结合
EXPLAIN
输出和实际慢查询场景一起看。

相关推荐