yii 2.0.45不生成mysql慢查询日志,需配置mysql服务端参数(slow_query_log、long_query_time等);诊断应结合explain分析真实sql、优化索引与yii查询写法,如预加载、字段精简、schema缓存。

Yii 2.0.45 本身不直接生成 MySQL 慢查询日志,它依赖底层 MySQL 的配置。真正起作用的是 MySQL 的 slow_query_log 和相关参数——Yii 只负责执行 SQL,而“是否被记录为慢查询”,完全由数据库服务端决定。所以调优的关键不是改 Yii,而是让 Yii 发出的 SQL 更容易被慢日志捕获、更容易被 EXPLAIN 看清、也更容易被索引覆盖。
确保慢查询日志能抓到 Yii 发出的语句
很多 Yii 应用线上跑着,MySQL 慢日志却空空如也,问题往往出在阈值和开关没对上:
-
必须动态开启并设低阈值:在 MySQL 中执行
SET GLOBAL slow_query_log = ON;<br>SET GLOBAL long_query_time = 1;<br>SET GLOBAL log_queries_not_using_indexes = ON;
注意:long_query_time = 1是生产环境较合理的起点;设为0.5或0(记录所有)仅用于短时排查,避免日志爆炸。 -
Yii 的绑定参数会掩盖真实执行耗时:你看到日志里是
WHERE id = ?,但实际可能是WHERE id = 9999999——这个值若落在数据末尾,配合LIMIT就极易触发深分页扫描。别只看日志里的模板,要用pt-query-digest或mysqldumpslow -s t聚合后看Rows_examined和Rows_sent的比值,比值越大越可疑。 -
确认日志路径有写权限:MySQL 进程用户(如
mysql)必须能往slow_query_log_file指定路径写入,否则静默失败。
让 EXPLAIN 真正看清 Yii 查询的执行路径
Yii 的 ActiveRecord 查询最终都会转成原生 SQL。想诊断,不能只信 Yii 日志里那句“耗时 86ms”,得亲手跑 EXPLAIN:
-
先拿到真实 SQL:在控制器或调试中加一行
echo $query->createCommand()->getRawSql();
复制输出的 SQL(注意替换?占位符为实际值,尤其是字符串要加引号),再粘贴进 MySQL 客户端执行EXPLAIN [SQL]。 -
紧盯 type 和 key:
–type = ALL或index→ 全表/全索引扫描,危险信号;
–key = NULL→ 完全没走索引;
–Extra出现Using filesort或Using temporary→ORDER BY或GROUP BY没被索引覆盖。 -
警惕 Yii 自动加的隐式条件:比如
$model->find()->where(['status' => 1])->all(),如果 status 是字符串类型字段,而传入的是整数1,MySQL 会做隐式转换,导致索引失效。统一用字符串传参:['status' => '1']。
Yii 层面能立刻见效的性能加固项
这些不改 SQL 逻辑,但能显著降低数据库压力和误判率:
-
关闭调试模式:入口文件
web/index.php第一行必须是defined('YII_DEBUG') or define('YII_DEBUG', false);
同时检查配置中没在别处重定义该常量。开启调试时,每个请求额外增加 20–30ms 开销,高并发下放大效应明显。 -
启用 schema 缓存:在
config/web.php的db组件中明确配置:'enableSchemaCache' => true,<br>'schemaCache' => 'cache',<br>'schemaCacheDuration' => 3600,
并确保cache组件已启用(如 Redis 或 FileCache)。否则每次 new Model 都查information_schema,纯属浪费。 -
避免 N+1 和无谓字段:
– 关联查询用with()预加载,别在循环里反复->getRelation();
– 只查需要的字段:select(['id', 'name', 'status']),不用SELECT *;
– 大量数据导出或列表页,加asArray(),跳过 ActiveRecord 实例化开销。
索引优化要匹配 Yii 查询模式
Yii 常见的查询组合,决定了索引该怎么建:
-
等值 + 排序场景:比如
->where(['user_id' => 123, 'status' => 'paid'])->orderBy('created_at DESC'),建联合索引应为(user_id, status, created_at),而不是(user_id, created_at)—— 因为status是等值条件,放前面才能让后续created_at有序。 -
LIKE 查询别踩坑:Yii 写
['like', 'name', 'abc']默认生成name LIKE '%abc%',索引无效;如需索引加速,得手动写name LIKE 'abc%'并确保字段有前缀索引或完整索引。 -
时间范围慎用函数:不要写
->andWhere(['>=', 'DATE(created_at)', '2026-10-01']),这会让索引失效;应改用范围查询:->andWhere(['>=', 'created_at', '2026-10-01 00:00:00'])。











