本文目录导读:

在 PHP 中抓取慢查询,通常涉及两个层面:数据库慢查询 和 PHP 自身执行慢,下面我分两部分详细说明,并给出最佳实践方案。
数据库慢查询(MySQL)
MySQL 慢查询日志(最常用)
-- 查看当前状态 SHOW VARIABLES LIKE 'slow_query_log%'; SHOW VARIABLES LIKE 'long_query_time'; -- 开启慢查询(临时) SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 1; -- 记录超过1秒的查询 SET GLOBAL log_queries_not_using_indexes = 'ON'; -- 记录未使用索引的查询 -- 永久开启(my.cnf 配置) [mysqld] slow_query_log = 1 slow_query_log_file = /var/log/mysql/slow.log long_query_time = 1 log_queries_not_using_indexes = 1
查看慢查询日志:
# 使用 mysqldumpslow 工具分析 mysqldumpslow -s c -t 10 /var/log/mysql/slow.log # 实时查看 tail -f /var/log/mysql/slow.log
performance_schema(8.0+ 推荐)
-- 查询执行时间最长的SQL
SELECT
DIGEST_TEXT,
COUNT_STAR,
SUM_TIMER_WAIT/1000000000 AS total_seconds,
AVG_TIMER_WAIT/1000000000 AS avg_seconds
FROM performance_schema.events_statements_summary_by_digest
WHERE DIGEST_TEXT NOT LIKE '%performance_schema%'
ORDER BY avg_seconds DESC
LIMIT 10;
使用 pt-query-digest(Percona Toolkit)
# 安装后使用 pt-query-digest /var/log/mysql/slow.log > slow_analysis.txt pt-query-digest --since="1 hour ago" /var/log/mysql/slow.log
PHP 应用层面慢查询
启用内置查询日志(最推荐)
<?php
// 在数据库连接初始化处添加
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_TIMEOUT => 3, // 连接超时
];
// 使用 PDO 列子,自行封装记录慢SQL
class MySQLTrace {
private static $slowQueries = [];
public static function traceQuery($sql, $params = [], $threshold = 1.0) {
$start = microtime(true);
$result = self::query($sql, $params);
$elapsed = microtime(true) - $start;
if ($elapsed > $threshold) {
self::$slowQueries[] = [
'sql' => $sql,
'params' => $params,
'time' => $elapsed,
'time_str' => date('Y-m-d H:i:s')
];
// 可以记录到日志或发邮件
self::logSlowQuery();
}
return $result;
}
}
?>
使用框架内置的日志功能
Laravel 监听 SQL:
// AppServiceProvider.php
use Illuminate\Support\Facades\DB;
DB::listen(function ($query) {
if ($query->time > 1000) { // 超过1秒
Log::warning('慢SQL', [
'sql' => $query->sql,
'bindings' => $query->bindings,
'time' => $query->time
]);
}
});
Symfony Doctrine:
// config/packages/doctrine.yaml
doctrine:
dbal:
connections:
default:
profiling: true
server_version: '%database_server_version%'
# 监听器
class SlowQueryLogger {
public function onKernelRequest(GetResponseEvent $event) {
$logger = $event->getRequest()->attributes->get('logger');
// 注册SQL日志记录器
}
}
使用 Tinker/自定义工具(小型项目)
<?php
// 创建一个通用查询函数
function query($sql) {
$start = microtime(true);
$result = DB::query($sql);
$elapsed = microtime(true) - $start;
if ($elapsed > 1) {
error_log("[SLOW] " . date('Y-m-d H:i:s') . " - " . $elapsed . "s - " . $sql . "\n", 3, "/tmp/slow_php.log");
}
return $result;
}
生产环境最佳实践组合
组合方案推荐
# 1. 系统监控(OPCache, Xdebug Profile) php -d xdebug.mode=profile -d xdebug.profiler_output_dir=/tmp/profiles -d xdebug.profiler_output_name=trace.%s.xt php test.php # 2. 使用 Blackfire / Tideways(商业工具价格高但功能强大) # 3. 引入 APM 工具(如 New Relic, Datadog,开源的用 Skywalking/Pinpoint) # 4. 日志记录 + 监控告警
轻量级解决(Laravel 优雅方案)
<?php
// app/Providers/AppServiceProvider.php
public function boot()
{
DB::listen(function ($query) {
$threshold = config('app.slow_query_threshold');
if ($query->time > $threshold) {
Log::channel('database')->warning('慢查询', [
'sql' => $query->sql,
'bindings' => $query->bindings,
'time_ms' => $query->time,
'url' => request()->fullUrl(),
'session_id' => session()->getId()
]);
}
});
}
实时监控与告警
简单监控脚本
<?php
// monitor_slow.php - 定时执行
$cmd = "pt-query-digest /var/log/mysql/slow.log --since='5 minutes' --limit=5";
exec($cmd, $output, $return);
if ($return == 0) {
$slowQueries = implode("\n", $output);
if (strlen($slowQueries) > 100) {
// 发送邮件/钉钉通知
sendNotify("发现慢查询", $slowQueries);
}
}
终极建议
- 优先使用 MySQL 原生慢日志——最有效且影响最小
- 应用程序内增加慢查询探针——能记录到具体的业务上下文
- 定期分析与优化——用
pt-query-digest每周分析一次 - 建立SOP: 一旦发现慢查询,按照:
查询执行计划 → 索引检查 → SQL重写 → 缓存优化顺序处理 - 监控级联: 把慢查询和基础设施监控(CPU、内存、连接数)联动起来
实际案例参考
# 某电商系统,他们通过以下方式定位问题: # 1. MySQL slow log 里发现了一个跑了 25 秒的查询 # 2. app 内日志显示这个查询在 14:30 - 14:45 出现高频调用 # 3. 结合 Redis 缓存发现缓存穿透,最终通过改造 SQL 加索引和 Redis 三层缓存解决
这套组合拳基本能覆盖绝大多数 PHP 慢查询场景,关键是要尽早建立监控体系,而不是等到用户反馈才去排查。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播