为什么加了索引查询还是慢
索引不是万能的,
WHERE条件没用上索引列、用了函数或类型隐式转换、或者查询返回大量行,都会让索引失效。比如写
WHERE YEAR(create_time) = 2023,MySQL 无法使用
create_time上的普通 B+ 树索引;又比如
WHERE user_id = '123',而
user_id是
INT类型,字符串比较会触发隐式转换,导致索引跳过。
实操建议:
用EXPLAIN查看
type是否为
ref/
range,
key是否显示实际使用的索引名 避免在索引列上做计算、函数调用、
LIKE '%xxx'开头匹配 确保查询条件的数据类型和字段定义完全一致(如
INT对
INT,不是
INT对
VARCHAR)
复合索引的最左前缀怎么生效
MySQL 的复合索引(如
(a, b, c))只支持从左到右连续匹配。这意味着它可以加速
WHERE a = ?、
WHERE a = ? AND b = ?、
WHERE a = ? AND b = ? AND c = ?,但对
WHERE b = ?或
WHERE a = ? AND c = ?(跳过
b)无效。
实操建议:
把高频等值查询字段放最左,范围查询(>、
BETWEEN)字段放中间,排序/分组字段放最后 如果常查
status和
created_at,但
status只有 3 个值,而
created_at高度离散,应建
(status, created_at)而非反过来 不要盲目堆字段:超过 3 列的复合索引维护成本高,且命中率未必提升
什么时候该用覆盖索引
覆盖索引指查询所需的所有字段都包含在索引中,无需回表查聚簇索引。例如表有
id、
name、
status,而你执行
SELECT name, email FROM users WHERE status = 'active',若存在索引
(status, name, email),就能直接从索引页拿到全部数据。
实操建议:
对高频、轻量级查询(如列表页只展示几个字段),优先考虑覆盖索引减少 I/O 注意索引大小:把大字段(如TEXT、长
VARCHAR)放进索引会显著增大索引体积,得不偿失 用
EXPLAIN看
Extra列是否含
Using index,这是覆盖索引生效的明确信号
唯一索引和普通索引选哪个
唯一索引(
UNIQUE)在写入时多一次重复值校验,但对读性能几乎无影响;普通索引允许重复,写入略快。真正关键区别在于语义和锁行为:唯一索引在
INSERT ... ON DUPLICATE KEY UPDATE或
REPLACE INTO场景下能精准定位冲突行,减少锁范围。
实操建议:
业务上要求唯一性的字段(如order_no)必须建
UNIQUE,既是约束也是性能保障 主键默认是聚簇唯一索引,不要额外建
UNIQUE(id)如果只是想加速查询,且字段天然不唯一(如
status),用普通索引即可,别强行加
UNIQUE
索引优化最易被忽略的点:不是“有没有索引”,而是“查询是否真的走到了它”。很多慢查根源不在 SQL 写法,而在统计信息过期、索引碎片、或缓冲池未预热——这些不会报错,但会让执行计划严重偏离预期。
