缓存每日统计查询可显著提升性能。使用Cache::remember()封装查询并设24小时缓存,或预生成+定时刷新;键名应语义化、避免硬编码,写操作后主动清理;配合索引与精简查询确保首次生成高效。

每日数据统计这类查询通常读多写少、结构固定、结果稳定,非常适合用缓存来跳过数据库执行,直接返回预计算或快照结果。Laravel 9 提供了简洁可靠的缓存接口,配合合理的策略,能将原本几百毫秒的聚合查询降到几毫秒内响应。
用 remember() 封装统计查询
这是最直接有效的方式。把整个 Eloquent 或 Query Builder 查询包裹在 Cache::remember() 中,设置缓存时间为 24 小时(或到次日零点),让结果只在每天首次请求时计算一次:
-
基础用法:
User::whereDate('created_at', today())->count();→ 改为Cache::remember('daily_user_count', 1440, fn() => User::whereDate('created_at', today())->count()); -
更精准控制失效时间:可传入
Carbon::tomorrow()->startOfDay()作为到期时间,避免跨天误差 -
带条件的统计也适用:比如“今日付费用户数”,同样套一层 remember,键名带上语义(如
'daily_paying_users')便于维护
预生成+定时刷新,避开请求时计算
如果统计逻辑较重(含多表 JOIN、GROUP BY、SUM/COUNT 组合),不建议依赖首次访问触发计算。应改为主动预热:
- 写一个 Artisan 命令(如
php artisan stats:refresh-today),内部执行全部统计并写入缓存,键名统一加前缀(如stats:daily:users) - 在
app/Console/Kernel.php中注册定时任务:$schedule->command('stats:refresh-today')->dailyAt('00:05');,确保每天凌晨 5 分钟内完成更新 - 接口中直接取值:
Cache::get('stats:daily:users', 0),零延迟返回
缓存键设计与清理要点
缓存不是扔进去就完事,键名和生命周期管理决定是否可持续:
-
避免硬编码键名:用常量或配置项定义,例如
config('cache.keys.daily_users'),方便统一替换和监控 -
写操作后主动清理:如果允许后台补录昨日数据,需在保存后调用
Cache::forget('daily_user_count'),否则缓存不会自动更新 - 不要依赖缓存自动过期做业务逻辑判断:比如“是否已统计”应以缓存是否存在为准,而不是靠时间戳字段——因为缓存可能被手动清空或 Redis 重启丢失
配合数据库索引与查询精简
缓存虽快,但首次生成仍要查库。确保底层查询本身高效:
-
为日期字段建索引:如
created_at,且用whereDate()时,MySQL 能命中索引(注意不是所有版本都支持函数索引,必要时改用whereBetween()) -
避免 SELECT * 或加载模型实例:统计类查询一律用
DB::table()或count()/sum()/value()等原生聚合方法,不走 Eloquent 模型生命周期 -
大表考虑物化视图思路:用定时任务把结果写入一张
daily_stats表,缓存则从这张轻量表读,进一步解耦


















