本文目录导读:

在 PHP 项目中配置数据库慢查询日志,主要涉及数据库层面(MySQL/MariaDB) 的配置,而不是 PHP 代码本身,PHP 通常通过 PDO 或 MySQLi 等扩展连接数据库,慢查询的检测和记录是由数据库服务器完成的。
以下是在 MySQL/MariaDB 中配置慢查询日志的详细步骤,以及在 PHP 项目中的一些辅助排查思路。
核心概念
- 慢查询日志(Slow Query Log):记录执行时间超过指定阈值的 SQL 语句。
long_query_time:阈值,单位是秒,建议设置为1或2(生产环境推荐1秒或更低)。slow_query_log:是否开启日志,ON或OFF。slow_query_log_file:日志文件路径。
配置步骤
方法 1:修改 MySQL 配置文件(持久化,推荐)
适用于 Linux 系统(/etc/my.cnf、/etc/mysql/my.cnf 或 /etc/mysql/mysql.conf.d/mysqld.cnf)或 Windows(my.ini)。
-
编辑配置文件(以 Linux 为例):
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
-
在
[mysqld]段落中添加或修改:[mysqld] # 开启慢查询日志 slow_query_log = 1 # 设置阈值(秒),2 秒 long_query_time = 2 # 日志文件路径(确保 MySQL 用户有写入权限) slow_query_log_file = /var/log/mysql/mysql-slow.log # 可选:记录未使用索引的查询(用于分析索引设计问题) log_queries_not_using_indexes = 1 # 可选:记录管理语句(如 ALTER TABLE 等) log_slow_admin_statements = 1
-
保存文件并重启 MySQL 服务:
sudo systemctl restart mysql # 或:service mysql restart
方法 2:动态修改(无需重启,临时生效)
通过 MySQL 客户端直接设置,重启后会失效。
-- 开启慢查询日志 SET GLOBAL slow_query_log = 'ON'; -- 设置阈值(秒) SET GLOBAL long_query_time = 2; -- 对于已连接会话,需要重新连接才生效 -- 查看当前配置 SHOW VARIABLES LIKE 'slow_query_log%'; SHOW VARIABLES LIKE 'long_query_time%';
验证配置是否生效
-
检查变量:
SHOW VARIABLES LIKE 'slow_query%'; SHOW VARIABLES LIKE 'long_query_time';
-
手动触发一个慢查询(
SELECT SLEEP(3)):SELECT SLEEP(3); -- 3 秒,大于阈值 2 秒
-
查看日志文件:
sudo tail -f /var/log/mysql/mysql-slow.log
应该能看到类似以下记录:
Time: 2024-05-27T10:30:00.123456Z User@Host: root[root] @ localhost [] Query_time: 3.000512 Lock_time: 0.000000 Rows_sent: 1 Rows_examined: 0 SET timestamp=1716815400; SELECT SLEEP(3);
慢查询日志分析工具
配置好日志后,需要定期分析,而不是只查看原始文件。
mysqldumpslow(MySQL 自带)
# 统计总耗时排序前10的慢查询 sudo mysqldumpslow -s t -t 10 /var/log/mysql/mysql-slow.log # 统计平均耗时排序 sudo mysqldumpslow -s at -t 10 /var/log/mysql/mysql-slow.log
pt-query-digest(Percona Toolkit,强烈推荐)
这是一个强大的开源工具,能分析查询模式、频率和总体影响。
# 安装 sudo apt install percona-toolkit # 分析慢查询日志 sudo pt-query-digest /var/log/mysql/mysql-slow.log
PHP 项目中的辅助排查
虽然慢查询主要靠数据库自身记录,但 PHP 侧可以配合以下方法定位问题:
日志记录绑定参数
PHP 使用 PDO 预编译语句(Prepared Statement),慢查询日志中可能只显示 INSERT INTO ... VALUES (?, ?, ?) 而非实际值,不利于排查具体参数。
解决方法:开启 PHP 的 General Query Log(谨慎,仅用于开发或低负载环境)。
// 在 PHP 配置中(或在运行时动态设置)
ini_set('mysql.trace_mode', 1); // 仅用于 MySQL 扩展
// 或使用 PDO 的 setAttribute 设置模拟模式
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
更好的做法:在 PHP 业务代码中自行记录慢操作。
在 PHP 中主动记录超时查询
封装数据库查询方法,检测耗时。
<?php
function queryWithTimeLog($sql, $params = []) {
$start = microtime(true);
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
$time = (microtime(true) - $start);
if ($time > 1.0) { // 阈值 1 秒
error_log("Slow query ({$time}s): {$sql} | Params: " . json_encode($params), 3, '/tmp/php-slow.log');
}
return $stmt;
}
注意事项
- 日志文件权限:确保 MySQL 运行用户(通常是
mysql)对日志目录有写入权限。 - 磁盘 I/O 影响:慢查询日志会写入磁盘,高并发环境下可能增加 I/O 压力,生产环境中不建议
log_queries_not_using_indexes始终开启,因为即使很短的查询也会被记录,导致日志迅速膨胀,建议仅在排查阶段临时开启。 - 不要记录所有查询:不要开启
general_log(通用查询日志),除非是调试目的,因为它会记录所有 SQL,性能影响非常大。 - 定期清理:设置日志轮转(
logrotate)或手动清理,避免占用过多磁盘空间。
# 日志轮转配置(位于 /etc/logrotate.d/)
/var/log/mysql/mysql-slow.log {
daily
rotate 7
missingok
compress
delaycompress
notifempty
create 640 mysql adm
}
- 核心:在数据库端配置
slow_query_log和long_query_time。 - 工具:用
pt-query-digest或mysqldumpslow分析日志。 - PHP 端:结合自身代码记录耗时长的查询参数,辅助定位。
生产环境推荐配置示例:
slow_query_log = 1 long_query_time = 2 slow_query_log_file = /var/log/mysql/slow.log log_slow_admin_statements = 1 # log_queries_not_using_indexes = 0 # 默认关闭,避免日志过多
这样配置后,超过 2 秒的查询会自动记录到 /var/log/mysql/slow.log,你再配合分析工具定期查看即可。