索引并非万能,where条件未用索引字段、使用函数或隐式转换、违反最左前缀原则均会导致失效;explain可诊断type和key列;order by无索引或未覆盖时性能骤降;大偏移分页应改用游标。

为什么加了索引查询还是慢
索引不是万能的,WHERE 条件没用上索引字段、用了函数或类型隐式转换、索引列顺序不匹配复合索引最左前缀原则,都会导致索引失效。比如 SELECT * FROM users WHERE YEAR(create_time) = 2023,哪怕 create_time 有索引,MySQL 也无法跳过全表扫描。
- 用
EXPLAIN看type是否为range或更优(const/ref),避免ALL - 检查
key列是否显示实际使用的索引名,key_len是否符合预期长度 - 避免在索引列上做运算:
WHERE status + 0 = 1→ 改成WHERE status = 1 - 字符串比较注意字符集和排序规则一致,否则可能触发隐式转换,使索引失效
ORDER BY 和 LIMIT 配合时的性能陷阱
当 ORDER BY 字段没索引,或索引无法覆盖排序+查询需求,MySQL 可能先排序再取 LIMIT,极端情况要扫描并排序几百万行才返回前 20 条。
- 确保
ORDER BY字段有索引;若还带WHERE,优先建复合索引,如WHERE category = ? ORDER BY created_at DESC→ 建(category, created_at) - 避免
SELECT *配合大偏移量分页:LIMIT 10000, 20仍需跳过前 10000 行;改用游标方式(记录上一页最大created_at,下一页查WHERE created_at ) - 如果业务允许,把排序逻辑移到应用层(仅限数据量小、排序规则简单场景)
JOIN 查询慢,到底是驱动表选错了还是没走索引
MySQL 的 JOIN 是嵌套循环,驱动表(外层)越小,整体扫描代价越低。但优化器不一定总选对——尤其当统计信息过期、或 WHERE 条件分散在多张表时。
- 用
EXPLAIN观察table列顺序:排在第一行的是驱动表;若大表在前,考虑用STRAIGHT_JOIN强制小表驱动(慎用,需配合测试) - 被驱动表的
ON或WHERE条件字段必须有索引,否则是ALL关联,复杂度爆炸 - 避免
SELECT *在 JOIN 中,只取真正需要的字段,减少临时表和网络传输开销 - 关联字段类型务必一致(如都是
BIGINT),否则隐式转换会让索引失效
哪些配置项会直接影响单条查询响应时间
有些参数不改不影响启动,但一到复杂查询就暴露问题,比如临时表撑爆内存、排序缓冲区太小被迫磁盘排序。
-
sort_buffer_size:每个线程独占,设太大易引发内存争抢;一般 256K–2M 足够,勿全局设成 128M -
tmp_table_size和max_heap_table_size:需保持一致,控制内存临时表上限;超过则转磁盘(MyISAM临时表),性能断崖下跌 -
join_buffer_size:影响无索引 JOIN 的性能,但只在没用上索引时生效;优先修复索引,而非盲目调大 -
innodb_buffer_pool_size:必须占物理内存 50%–75%,否则大量数据页要反复从磁盘读,再好的 SQL 也快不起来
实际优化中,90% 的慢查根源不在 SQL 写法本身,而在索引设计与数据分布不匹配。别急着重写查询,先看 EXPLAIN 输出里有没有 Using filesort 或 Using temporary —— 这两个提示往往比执行时间更早暴露问题。











