需手动启用MySQL慢查询日志,配置slow_query_log、slow_query_log_file、long_query_time等参数并重启;再用mysqldumpslow分析日志,EXPLAIN检查执行计划,结合PHP应用层排查循环查库、N+1、未分页等问题,最后按最左前缀原则建索引并验证效果。

开启慢查询日志并准确定位问题SQL
MySQL 默认不记录慢查询,需手动启用。在 my.cnf(或 my.ini)中添加以下配置:
- slow_query_log = ON
- slow_query_log_file = /var/log/mysql/slow.log(路径需有写入权限)
- long_query_time = 1(单位秒,建议先设为 1,线上可调至 0.5 或更低)
- log_queries_not_using_indexes = OFF(初期可关闭,避免干扰;确认慢查后可打开辅助诊断)
重启 MySQL 生效后,用 mysqldumpslow 工具快速汇总分析,例如:
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log —— 按执行时间倒序取前 10 条。
用 EXPLAIN 分析执行计划,识别性能瓶颈
拿到慢 SQL 后,不要直接优化,先加 EXPLAIN 看执行计划。重点关注这几列:
- type:值为 ALL 表示全表扫描,通常需加索引;range、ref 较健康;const 最优
- key:实际使用的索引名,若为 NULL,说明没走索引(可能因字段类型不匹配、函数包裹、隐式转换等)
- rows:预估扫描行数,远大于结果集行数时,说明索引效率低或未覆盖查询字段
- Extra:出现 Using filesort 或 Using temporary 是典型性能红灯,往往意味着排序/分组未走索引
注意:PHP 中拼接的 SQL 若含变量,务必用 PREPARE + EXECUTE 或 ORM 的原生查询方式获取真实执行计划,避免因参数不同导致执行计划偏差。
立即学习“PHP免费学习笔记(深入)”;
结合 PHP 应用层排查常见诱因
很多“慢查询”本质是应用逻辑导致的,而非 SQL 本身:
- 循环内查库:比如 foreach 用户列表,每次查一次用户订单——应改为 IN 批量查询或 JOIN 关联
- 未限制结果集:SELECT * FROM log_table WHERE status=0,无 LIMIT 且数据量大 → 加分页或归档旧数据
- ORM 使用不当:Eloquent 的 N+1 问题(如 $users->load('posts') 未预加载)、toArray() 触发大量访问器/关系加载
- 连接未复用或过早关闭:短生命周期脚本频繁 connect/disconnect,增加 TCP 开销;长任务中未及时释放结果集(mysqli_free_result),内存持续占用
可在 PHP 中用 microtime(true) 包裹数据库操作段,配合日志记录耗时,定位是 DB 延迟还是网络/序列化/业务逻辑拖慢。
索引优化与上线验证闭环
建索引不是越多越好,要围绕高频慢查和 WHERE / ORDER BY / GROUP BY 字段设计:
- 复合索引遵循 最左前缀原则,例如 WHERE a=1 AND b>2 ORDER BY c,适合建 (a,b,c) 索引
- 避免对 TEXT/BLOB 字段建全文索引以外的索引;避免在区分度极低的字段(如 is_deleted=0/1)单独建索引
- 上线前用 EXPLAIN FORMAT=JSON 查看是否命中新索引,并对比 rows 和 execution_time 变化
- 上线后观察慢日志是否消失、QPS/TPS 是否提升、CPU/IO 是否平稳——避免“索引解决了一个慢查,却拖慢了其他写操作”
对高并发表,考虑添加 pt-online-schema-change 工具在线加索引,避免锁表。











