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