ThinkPHP查询缓存需显式调用cache()方法才生效,非配置开启即自动缓存;SQL慢因索引缺失或N+1查询;生产环境须关闭debug与冗余日志;缓存键应带业务参数哈希以提升命中率。

ThinkPHP 查询缓存没生效?先确认 cache 配置和查询写法
ThinkPHP 的查询缓存不是开个开关就自动缓存所有 SQL,它只对明确调用 cache() 方法的查询生效。常见错误是以为配置了 'query_cache' => true 就万事大吉,其实这个配置只影响模型的 get()、select() 等方法在加了 cache() 后的行为,不加就不会进缓存。
实操建议:
-
cache()必须显式调用,比如UserModel::where('id', 1)->cache(3600)->find() - 缓存有效期单位是秒,传
0表示永久(依赖底层驱动如 Redis 的 TTL 策略) - 若用
Db::table(),需链式调用cache();模型方式同理,但注意作用域——关联查询、子查询默认不被缓存 - 缓存键由 SQL + 绑定参数 + 表名生成,所以带变量的 SQL(如
where('name', $name))能区分缓存,但拼接字符串("name = '$name'")会破坏一致性,且极不安全
SQL 慢在 JOIN 和 ORDER BY?先看执行计划再改写
ThinkPHP 不会帮你优化 SQL,它只是把你的逻辑翻译成 SQL。很多接口慢,根源是写了 N+1 查询或在大表上 ORDER BY created_at LIMIT 20 却没给 created_at 加索引。
实操建议:
- 用
Db::getLastSql()或日志开启sql_explain,拿到实际执行的 SQL,粘贴到 MySQL 客户端跑EXPLAIN - 如果
type是ALL或index,说明走了全表扫描;key为NULL表示没走索引 - ThinkPHP 中避免在循环里查关联数据,改用
with()预加载,但注意with(['profile', 'posts'])会生成多条 JOIN,大数据量时不如分两次查 + 关联 ID 合并 -
order()字段必须有索引,复合查询优先建联合索引,比如WHERE status=1 ORDER BY sort ASC, id DESC,索引应为(status, sort, id)
接口响应慢还卡在 PHP 层?关掉调试模式和日志冗余输出
开发环境开着 app_debug = true,ThinkPHP 会收集大量 trace 信息、SQL 日志、模板编译记录,这些在生产环境毫无意义,却吃掉 30%~50% 的响应时间。
实操建议:
- 生产环境必须设
app_debug = false,同时检查log.level是否为error,避免info级别日志刷屏 - 关闭模板自动编译:在配置中设
'template' => ['auto_rule' => false],改用php think build预编译 - 如果用了
halt()、dump()或未注释的trace()调试语句,上线前务必清空——它们不会因app_debug=false自动消失 - Redis 缓存驱动比 file 快一个数量级,哪怕只是做查询缓存,也值得把
cache.type改成redis并配好连接
为什么加了缓存还是慢?检查缓存键冲突和过期策略
缓存失效太快或缓存键太“宽”,会导致命中率极低。比如用 cache('user_list') 固定键,所有用户列表请求都挤在一个缓存项里,一刷新全崩;又或者用 cache(true) 让系统自动生成键,但字段顺序稍有不同(field('id,name') vs field('name,id'))就会生成不同键,重复查询也无法复用。
实操建议:
- 手动指定缓存键时,带上关键筛选条件哈希,比如
cache('user_list_' . md5($status . $type)) - 避免用
cache(true)处理复杂查询,ThinkPHP 生成的键对字段顺序、空格、换行敏感,极易不一致 - 缓存过期时间别拍脑袋定 60 秒,要结合业务更新频率:用户资料可缓 10 分钟,首页推荐位可能就得 30 秒
- 用
Cache::get('xxx')手动验证缓存是否存在,比等接口变快更直接;Redis 中可用redis-cli keys "*user*"快速排查键是否写入
缓存和 SQL 优化都是“点状生效”的事,改一处得验一处。最常被忽略的是缓存键的稳定性和 SQL 索引的实际覆盖范围,而不是框架本身有多慢。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










