tp6慢sql日志需用db::listen()事件监听实现,配置'sql_explain'=>true后在回调中判断$time>500毫秒并记录,需手动传入$request等上下文,不可依赖已移除的slow_query_time。

ThinkPHP 6.0 没有 slow_query_time 配置项,直接在 database.php 里加这个参数是无效的——它早在 TP6 发布时就被移除了。
TP6 怎么开慢 SQL 日志(不是 MySQL 自身的 slow log)
TP6 的慢查询日志必须靠事件监听实现,核心是 think\facade\Db::listen(),配合手动耗时判断。框架层不再自动拦截“超时 SQL”,你得自己写逻辑。
- 必须在应用初始化阶段注册监听,比如在
app/common.php或中间件中调用:Db::listen(function ($sql, $time, $explain) { if ($time > 500) { // 单位毫秒,按业务调整 Log::channel('slow_sql')->info('Slow SQL', [ 'sql' => $sql, 'time' => $time, 'explain' => $explain, ]); } }); -
$explain是可选参数,需在数据库配置中开启:'sql_explain' => true,否则为null - 不要在回调里直接写文件或发 HTTP 请求;高并发下会拖垮性能,应改用
Log::channel()配合异步驱动(如rocketmq或redis队列) - 生产环境务必加条件过滤,全量监听会让
Db::listen()本身成为瓶颈
为什么 Db::getLastSql() 查不到慢 SQL
Db::getLastSql() 只返回最近一次查询的原始 SQL 字符串,不带执行时间、参数绑定值、是否出错等任何上下文。它在事务、批量操作、子查询嵌套场景下极易指向错误目标。
- 例如:一个事务里执行了 5 条 SQL,第 3 条耗时 2s,但
Db::getLastSql()返回的是第 5 条 - 它不区分成功/失败,也不记录
$time,对“为什么慢”完全无帮助 - 真正可用的是
Db::listen()回调里的$time参数,这是唯一由框架精确测量并传入的耗时值
日志里看不到请求 URL 和用户 ID 怎么办
TP6 默认日志不携带 HTTP 上下文,Db::listen() 回调里也拿不到 $request 对象——闭包作用域隔离导致无法直接访问。
- 必须显式把关键上下文传进闭包,比如:
$request = app('request'); Db::listen(function ($sql, $time) use ($request) { if ($time > 500) { Log::channel('slow_sql')->info('', [ 'url' => $request->url(), 'ip' => $request->ip(), 'admin_id' => session('admin_id') ?: 0, 'sql' => $sql, 'time' => $time, ]); } }); - 注意:session 在 CLI 或 API Token 场景下可能为空,需做兜底(如填
0或null) - 如果用了 Swoole 或常驻进程,
session()可能复用旧数据,建议改用$request->header('x-user-id')等更可靠的透传方式
最易被忽略的是日志落盘时机:Swoole 模式下,runtime/log/ 日志可能缓存不刷盘,而 PHP-FPM 的 slowlog 是实时 flush 的。真要定位慢点,得同时比对 TP6 的监听日志 + PHP-FPM 的 slowlog + MySQL 的 slow_query_log,三者对照才能分清是 SQL 慢、PHP 执行慢,还是网络或扩展卡住。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











