thinkphp 5 商品列表查询优化需聚焦三要点:精简字段(用 field() 显式指定必要字段,关联表需在 with() 中裁剪)、手动缓存(显式 key、选对驱动、读-判-写逻辑)、分层缓存策略(敏感数据短 ttl、增删改后主动清理、禁用无效全局缓存)。

ThinkPHP 5 优化商品列表查询,核心不是“开了缓存就行”,而是让缓存真正命中、不拖慢、不脏读。重点在三件事:精简查什么、明确缓什么、控制怎么缓。
只查必要字段,先砍掉性能黑洞
商品列表通常带 content、description、details 这类大文本字段,不加限制会把整行数据拉上来,网络+内存双重浪费。
-
必须用
field(),且写在select()前:Db::name('goods')->field('id,title,price,cover_img,stock,status')->where('status',1)->select() - 别用字符串写法带空格:
field('id, title')会导致第一个字段截断;推荐数组写法更安全:field(['id','title as name','price']) - 如果用了关联(比如分类名、品牌名),
field()对关联表无效——得进with()闭包里裁剪:with(['category' => function($q){ $q->field(['id','name']); }]),且外键category_id必须保留
手动缓存结果,避免默认 cache() 的坑
TP5 默认所有查询都不走缓存,cache(true, 3600) 看似方便,但 key 是 SQL 的 MD5,换环境、加空格、改数据库前缀都会导致 key 变、缓存失效或错用。
- **显式定义 key**,带业务标识和参数特征:
$key = 'goods_list_status1_page_'.$page.'_'.$size; - **选对驱动**:静态商品列表(如后台管理页)可用
apcu(快、无网络开销);前台用户端高频访问建议用redis,并配置'persistent' => true防连接风暴 - **手动读-判-写**,逻辑清晰可控:
$data = Cache::store('redis')->get($key);<br> if (null === $data) {<br> $data = Db::name('goods')->field(...)->where(...)->paginate($size);<br> Cache::store('redis')->set($key, $data, 180); // 缓存3分钟,平衡新鲜度与压力<br> }
避开缓存陷阱,保障数据可信
商品价格、库存、上下架状态变频繁,缓存太久会误导用户;但全不缓存又扛不住流量。关键是“分层策略”:
-
不缓存敏感字段本身:列表里展示的
price和stock可缓存,但下单页、购物车页必须绕过缓存直查 DB 或用短 TTL(如 10 秒) -
增删改后主动清理:商品编辑、上架下架操作完成后,立刻执行:
Cache::store('redis')->delete('goods_list_status1_page_*');(支持通配需 Redis 6+)或按规则删具体 key,例如Cache::delete('goods_list_status1_page_1_20') -
禁用全局缓存开关:不要在
database.php里设'resultset_type' => 'collection'或盲目开启fields_cache,它缓的是表结构,对列表查询无直接帮助,还可能引发元数据不一致
补充:请求级缓存可作辅助(仅限纯 GET)
如果商品列表页是完全静态的展示页(无登录态判断、无用户偏好排序),可在路由中启用响应缓存:
- 在
route.php中:Route::get('goods/list', 'Goods/list')->cache(600); - 它返回 304 Not Modified,跳过 PHP 执行和模板渲染,但要求接口无 session、无 cookie 依赖,且前端要发标准 If-None-Match 请求头
- 不适用于含用户身份的个性化列表(如“猜你喜欢”),否则会缓存错误内容
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











