Yii2中拖慢请求的缓存配置包括:1.FileCache默认开启且未分区时高并发写入引发文件锁竞争;2.DbCache表缺少cache_key索引导致全表扫描;3.全局启用enableSchemaCache却未设schemaCacheDuration,致DB连接池耗尽;4.FragmentCache duration=0未手动invalidate导致页面不更新。

Yii2 中哪些缓存配置最容易拖慢请求
默认开启的 FileCache 在高并发写入场景下会成为瓶颈,尤其当缓存键含动态参数(如用户 ID)且未分区时,文件锁竞争明显。不是所有缓存都适合开,得看读写比和数据一致性要求。
-
FileCache仅适合开发或低流量环境;生产必须切到RedisCache或Memcached -
DbCache表没加索引(cache_key字段)会导致SELECT全表扫描,查一次缓存反而比直接查业务表还慢 - 全局启用
enableSchemaCache但没配schemaCacheDuration,会导致 DB 连接池被长连接占满,表现为MySQL server has gone away - 用
FragmentCache时,若duration设为0(表示永不过期),缓存不会自动失效,需手动调用invalidate(),否则页面永远不更新
ActiveRecord 的延迟加载(lazy loading)什么时候真·变慢
看似省资源的 getRelation() 自动触发查询,实际在循环里反复调用就会触发 N+1 查询——这不是 Yii 的 bug,是开发者没预判好关联加载时机。
- 遍历
User::find()->all()后对每个用户调用$user->profile,等于执行了 N 次SELECT * FROM profile WHERE user_id = ? - 正确做法是提前用
with('profile')预加载,或改用joinWith('profile', true)强制 JOIN(注意:后者在有分页时可能重复主表记录) -
viaTable关系中若中间表无复合索引(如(from_id, to_id)),JOIN 会走全表扫描,比 N+1 更糟 - 用
asArray()+with()时,关联数据会嵌套在数组里,但不会自动转成对象;如果后续又调用$row['profile']['name'],别误以为这是懒加载——它只是数组访问,没查库
OpCache 开启后 Yii2 为什么反而报错或不生效
OpCache 是 PHP 层优化,和 Yii 无关,但它的配置直接影响框架类自动加载和配置解析行为。常见问题不是 OpCache 本身坏了,而是它和 Yii 的缓存策略冲突了。
-
opcache.validate_timestamps=0(生产推荐)时,修改了config/web.php不重启 PHP-FPM 就不会生效——不是 Yii 缓存了配置,是 OpCache 缓存了整个 PHP 文件字节码 -
opcache.revalidate_path=1开启后,include/require路径含变量(如require __DIR__ . '/' . $env . '.php')会被 OpCache 忽略校验,导致环境切换失效 - Yii 的
ClassMapGenerator生成的映射文件如果被 OpCache 缓存,而你又删了某个类但没清 OpCache,Class not found错误会持续存在,哪怕文件已删 - 使用
apcu_clear_cache()清应用缓存无效?因为 OpCache 和 APCu 是两层独立缓存,得分别清:opcache_reset()和apcu_clear_cache()
哪些“优化操作”会让 Yii2 更慢而不是更快
有些做法看着像优化,实则是把简单问题复杂化,或者把缓存当成万能膏药乱贴。
- 给每个
ActiveRecord::findOne()都套一层yii\caching\Dependency(比如DbDependency),每次查缓存前先执行一次 SQL 判断是否过期——等于没省查询,还多了一次 DB 往返 - 在控制器里手动调用
Yii::$app->cache->set()存大量序列化模型对象,而不设key分区,导致缓存 key 冲突、GC 压力大、命中率暴跌 - 用
yii\log\FileTarget记录 debug 日志时,把maxFileSize设成1024(1KB),频繁滚动日志文件会触发大量磁盘 I/O,压垮小内存 VPS - 为“统一入口”把所有路由都扔进
UrlRule正则匹配,规则超 20 条后,每次请求都要遍历全部正则,比直接用 PATH_INFO 匹配慢 3 倍以上
最常被忽略的是:OpCache 的 opcache.memory_consumption 如果设得太小(比如 64M),而项目又用了大量扩展(如 Swagger、Debug Toolbar),OpCache 会频繁踢出旧脚本,反而增加编译开销。这个值不是越大越好,得看 opcache_get_status()['memory_usage'] 实际占用再调。











