PHP项目慢查询日志怎样解读

wen PHP项目 5

本文目录导读:

PHP项目慢查询日志怎样解读

  1. 第一步:确认日志是否开启及位置
  2. 第二步:看懂一条日志的核心字段(逐行拆解)
  3. 第三步:实战解读与排查策略(关键)
  4. 第四步:常见优化手段(对症下药)
  5. 第五步:实战案例(举一反三)
  6. 关键提示:PHP 自身的“慢日志”在哪?

在 PHP 项目中,慢查询日志通常指的是数据库(MySQL)层面的日志,而不是 PHP 自身的日志,解读它的核心目的是精准定位拖慢系统的 SQL 语句,并找到优化的切入点。

以下是系统的解读步骤和实战技巧:

第一步:确认日志是否开启及位置

你需要找到日志文件,在 MySQL 中,通常执行以下命令(如果在命令行):

SHOW VARIABLES LIKE 'slow_query_log%';
SHOW VARIABLES LIKE 'long_query_time';
  • slow_query_log:是否开启(ONOFF)。
  • slow_query_log_file:日志存放的物理路径。
  • long_query_time:阈值(默认 10 秒,通常建议调低到 2 秒或 1 秒)。

第二步:看懂一条日志的核心字段(逐行拆解)

假设你从日志中抓取了这样一条记录:

# Time: 2023-10-01T10:23:45.123456Z
# User@Host: root[root] @ localhost [127.0.0.1]  Id: 12345
# Query_time: 5.234567  Lock_time: 0.002345 Rows_sent: 1000  Rows_examined: 500000
SET timestamp=1696148625;
SELECT * FROM orders WHERE user_id = 101 AND status = 'completed' ORDER BY created_at DESC LIMIT 1000;

解读逻辑如下:

参数 含义 健康标准/警惕点
Query_time 总执行耗时(5.23秒) 这是主角,若远高于阈值,说明 SQL 本身有问题或缺索引。
Lock_time 锁等待时间(0.002秒) 通常较小,如果锁时间接近 Query_time,说明并发冲突严重(锁表/锁行)。
Rows_examined 扫描了多少行(50万行) 重点排查项,如果这个数字巨大,且 Rows_sent 很小(1000),说明发生了全表扫描,这是主要优化方向。
Rows_sent 返回了多少行(1000行) 通常业务需求决定的,如果发送太多,检查是否 SELECT * 或缺少 LIMIT
SET timestamp 语句执行的具体时间戳 用于定位是业务高峰期还是定时任务导致的。

第三步:实战解读与排查策略(关键)

拿到一条日志后,按照以下顺序快速定位病根:

Rows_examinedRows_sent 的比例

  • 场景 AExaminedSent 大 100 倍以上。
    • 索引失效或缺失
    • 动作:直接对 WHERE 条件字段(user_id, status)和排序字段(created_at)建立联合索引
  • 场景 BExaminedSent 差不多,但 Query_time 仍然很慢。
    • 数据量大,但可能是网络传输慢,或者是返回数据行数太多导致序列化时间长。
    • 动作:检查是否需要分页(LIMIT),或减少 SELECT 的字段(避免 SELETE *)。

具体区分“慢”的类型

  • 全是 Rows_examined 大:优先加索引。
  • 全是 Lock_time 大:优先看数据库连接池,检查是否有长事务(事务未提交导致锁等待)。
  • Query_time 大,但统计值都很小:可能是数据库服务器 CPU 繁忙,或查询涉及复杂的子查询/大表 JOIN

看时间分布(Time 字段)

  • 如果都在下午 2:00 - 3:00 集中出现,可能是定时任务(如数据同步)报表跑批
  • 如果高并发时出现,通常是缓存失效导致并发穿透,或者慢 SQL 拖垮了数据库连接池

第四步:常见优化手段(对症下药)

根据解读结果,通常采取以下措施:

  1. 加索引(最核心):对于 WHEREORDER BY 的字段,建立复合索引,注意字段顺序(区分度高的放最左)。
  2. 改写 SQL:避免 SELECT *,避免 LIKE '%xx' 前置模糊查询,避免在索引列上做函数运算(如 LEFT(phone, 3))。
  3. 分页优化:经典的深分页问题(LIMIT 500000, 20),可改为 WHERE id > 500000 LIMIT 20(延迟关联)。
  4. 未命中缓存:如果该 SQL 是高频查询且短小,可考虑在 Redis 中缓存结果集,减少数据库压力。

第五步:实战案例(举一反三)

案例日志

# Query_time: 2.8  Lock_time: 0.0 Rows_sent: 10 Rows_examined: 400000
SELECT * FROM products WHERE category = 'electronics' AND price > 1000;

解读:扫描了 40 万行只给了 10 条,明显缺索引

优化动作

ALTER TABLE products ADD INDEX idx_cat_price (category, price);

执行后,Rows_examined 会骤降至 10 行左右,Query_time 下降至 0.01 秒。


关键提示:PHP 自身的“慢日志”在哪?

如果你看到的日志不是这种格式,而是类似于 [pool www] slow request(PHP-FPM 慢日志),那解读逻辑是另一回事,但目前 90% 的 PHP 性能瓶颈都在数据库慢查询,而非 PHP 本身

补充建议:如果项目使用的是 Laravel 或 Symfony,请开启 DB::listen 事件监听,它可以直接在日志里打印 SQL 和参数,便于快速对应业务代码。

抱歉,评论功能暂时关闭!