超级管理员
楼主
数据库慢查询是最常见的性能问题,也是最容易误诊的一类。分享一个优化思路。
第一步:先确认是数据库的问题 很多「数据库慢」其实是:
- 应用层的 N+1 查询。循环里查数据库,100 次循环就是 100 次往返。
- 连接池配置不当。连接数不够,请求在排队等连接。
- 网络延迟。应用和数据库跨机房,每次往返几十毫秒。
- 返回数据量过大。查了 10 万行只用前 10 行。
先用一个简单判断:把那条 SQL 单独在数据库客户端里跑,记时间。如果很快,问题在应用层或网络;如果也慢,才是 SQL 本身。
第二步:看执行计划 EXPLAIN 是起点,但要看懂几个关键字段:
- type(访问类型):system > const > eq_ref > ref > range > index > ALL。出现 ALL(全表扫描)或 index(全索引扫描)要警惕。
- key:实际用到的索引。如果是 NULL,说明没走索引。
- rows:预计扫描行数。这个数字和返回行数的比值,是判断效率的核心指标。
- Extra:Using filesort 和 Using temporary 通常意味着性能问题。
第三步:为什么索引没生效 这是最常见的困惑。常见原因:
- 违反最左前缀。复合索引 (a, b, c),查询条件只有 b 和 c 就用不上。
- 在索引列上做了运算或函数。
WHERE YEAR(create_time) = 2026用不上索引,改成范围查询可以。 - 隐式类型转换。字符串列传了数字,或者反过来。
- OR 连接。某些情况下会导致索引失效。
- 统计信息过时。优化器基于统计信息做判断,统计不准会选错计划。定期 ANALYZE TABLE。
- 选择性太差。状态列只有几个取值,即使用索引也要扫大量行,优化器会选择全表扫描——这时候它的判断是对的。
第四步:优化手段(按优先级)
- 加合适的索引。注意复合索引的字段顺序:等值查询的在前,范围查询的在后。
- 改写查询。避免 SELECT *,只取需要的字段;用 JOIN 替代子查询(多数情况下);拆分复杂查询。
- 加缓存。读多写少的数据,缓存比优化 SQL 更有效。
- 改表结构。冗余字段、汇总表、分区。这是最后的手段。
几个容易忽略的点
- 索引不是越多越好。每个索引都会拖慢写入,还占空间。
- 覆盖索引。如果查询的字段都在索引里,就不用回表,性能提升明显。
- 深分页。
LIMIT 100000, 20要扫描 100020 行。改成用主键游标:WHERE id > last_id LIMIT 20。 - 记录慢查询日志。开启 slow query log,定期分析 Top N。
一条原则 优化之前先测量,优化之后还要测量。凭感觉改索引,很可能把某个查询变快的同时让另一个变慢。
本文由奇幻维度内容助手整理发布,欢迎在评论区交流你的看法。