应使用时间区间查询替代 wheredate,如 ->where('created_at', '>=', today())->where('created_at', '

在 Laravel 11 中统计每日数据(如“今日订单数”“今日用户注册量”)看似简单,但若不加优化,容易在数据量上升后出现响应延迟、CPU 占高甚至超时。关键不在写法多炫酷,而在于让数据库少干活、只查该查的、用对索引、避开常见陷阱。
精准限定时间范围,避免函数操作导致索引失效
统计“今日”最常用写法是 whereDate('created_at', today()),但这个函数会绕过 created_at 字段上的索引,强制全表扫描。
正确做法是用时间区间替代:
- 用
Carbon::today()和Carbon::tomorrow()构造闭开区间:->whereBetween('created_at', [today(), tomorrow()]) - 或更明确地写成:
->where('created_at', '>=', today())<br>->where('created_at', ' - 确保
created_at字段已建单列索引;若还常按状态筛选(如status = 'paid'),建议建复合索引:$table->index(['status', 'created_at']);
只查计数,不查记录,禁用模型实例化开销
统计类查询的目标是数字,不是模型对象。用 count() 而非 get()->count() 或 all(),前者生成 SELECT COUNT(*),后者先取全部数据再 PHP 计数,内存和网络双重浪费。
示例对比:
- ✅ 推荐:
Order::where('status', 'paid')<br> ->whereBetween('created_at', [today(), tomorrow()])<br> ->count(); - ❌ 避免:
Order::where(...)->get()->count();(加载全部模型再计数)Order::where(...)->all();(更危险)
高频统计场景考虑缓存,但注意时效性边界
如果“今日订单数”被首页、管理后台、API 多处调用,且业务允许最多 1 分钟延迟,可用 remember() 缓存结果:
Order::where('status', 'paid')<br> ->whereBetween('created_at', [today(), tomorrow()])<br> ->remember(60)<br> ->count();- 缓存键自动包含查询条件,无需手动拼接
- 注意:软删除字段(
deleted_at)若未索引,缓存虽快,但首次计算仍慢——务必为deleted_at加索引,或建覆盖索引(deleted_at, status, created_at)
关联统计需谨慎,优先用原生 JOIN 或子查询
例如统计“每个用户今日下单数”,别直接循环查 + withCount(易 N+1),也别无脑 withCount(['orders' => fn($q) => $q->today()])(可能触发多次子查询)。
更高效方式:
- 用
DB::table()+JOIN或LEFT JOIN ... GROUP BY一次查出:DB::table('users')<br> ->leftJoin('orders', function ($join) {<br> $join->on('users.id', '=', 'orders.user_id')<br> ->whereBetween('orders.created_at', [today(), tomorrow()]);<br> })<br> ->select('users.id', 'users.name', DB::raw('COUNT(orders.id) as order_count'))<br> ->groupBy('users.id', 'users.name')<br> ->get(); - 若必须用 Eloquent,改用
selectRaw+groupBy,避免模型实例化











