跳转到主内容
极星编程网:以代码为星,赴技术山海!

mysql复合索引失效原因有哪些_mysql最左前缀匹配原则详解

联合索引必须满足最左前缀原则才有效,即查询须从索引最左列开始、连续使用等值条件;跳过中间列(如sn=?AND age=?缺name)或单独查右列(如name=?)均导致索引失效,范围查询还会截断右侧列的索引使用。 联合索引不满足最左前缀,直接失效 MySQL 的联合索引(如
INDEX idx_sn_name_age (sn, name, age)
)不是“多个字段随便查都行”,而是严格按定义顺序组织 B+ 树。只有从最左边字段开始、连续的等值条件才能命中索引。 常见错误现象:
WHERE name = '张三' AND age = 25
完全用不上
sn+name+age
索引;
WHERE sn = 'S001' AND age = 25
也只用到
sn
,
age
被跳过——因为中间缺了
name
,索引链断了。 ✅ 正确用法:
sn = ?
、
sn = ? AND name = ?
、
sn = ? AND name = ? AND age = ?
❌ 错误写法:
name = ?
、
age = ?
、
sn = ? AND age = ?
(跳过
name
) ⚠️ 注意:范围查询(
>
、
<
、
BETWEEN
)会截断右侧所有列的索引使用,比如
sn = ? AND name > 'a' AND age = 25
中,
age
就不会走索引 LIKE 模糊查询写错位置,索引当场消失 索引只对「前缀确定」的模糊匹配有效,因为 B+ 树是按字典序排序的,MySQL 能快速定位
'张%'
对应的起始页,但对
'%张'
或
'%张%'
,只能扫完整个索引甚至回表全扫。 真实场景中,搜索框默认带「包含」语义,但后端若直接拼成
LIKE '%${keyword}%'
,哪怕有
name
索引也白搭。 ✅ 可走索引:
name LIKE '张%'
、
name >= '张' AND name < '张\ufffd'
(手动模拟前缀) ❌ 不走索引:
name LIKE '%张'
、
name LIKE '%张%'
、
LEFT(name, 2) = '张'
(函数导致失效) ? 补救思路:高频「含某字」搜索可考虑全文索引(
FULLTEXT
)或引入 Elasticsearch,别硬扛 对索引列做计算、函数或隐式类型转换 只要 MySQL 在执行时需要先处理字段再比对,索引就大概率失效——因为索引存的是原始值,不是函数结果或转换后值。 MySQL(Linux) MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。 下载 典型例子:
WHERE age + 1 = 26
、
WHERE UPPER(name) = 'LISA'
、
WHERE name = 123
(
name
是
VARCHAR
,传入数字触发隐式转换)。 ✅ 安全写法:
age = 25
、
name = '123'
(字符串加引号)、
DATE(create_time) = '2026-03-19'
改为
create_time >= '2026-03-19' AND create_time < '2026-03-20'
❌ 高危操作:
WHERE YEAR(create_time) = 2026
、
WHERE CAST(age AS CHAR) = '25'
、
WHERE name + '' = 'abc'
? 验证方法:用
EXPLAIN
看
key
和
key_len
是否非空,
type
是否为
ref
/
range
,而非
ALL
OR 条件里混用无索引字段,整条路堵死 MySQL 一般不会为 OR 各自走不同索引再合并结果(除非开启
index_merge
且优化器判定划算)。更常见的是:只要 OR 中有一个分支没索引,整个 WHERE 就可能放弃索引,退化为全表扫描。 比如
WHERE status = 'active' OR user_id = 123
,如果
status
没索引,即使
user_id
有索引,也可能不走。 ✅ 替代方案:
UNION ALL
拆开(确保各子句能独立走索引):
(SELECT ... WHERE status = 'active') UNION ALL (SELECT ... WHERE user_id = 123)
✅ 或补索引:
status
加单列索引,或建覆盖索引
(status, user_id)
⚠️ 注意:
IN
通常比
OR
更友好,但
IN
列表过大(如上千项)也会让优化器放弃索引 最左前缀不是教条,而是 B+ 树物理结构决定的硬约束;失效往往不是 MySQL “不聪明”,而是我们写的 SQL 超出了索引能高效服务的边界。查慢查询时,第一眼盯
EXPLAIN
里的
key
和
Extra
(尤其是
Using filesort
、
Using temporary
),比猜原因快得多。

相关文章