You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在数据库中批量统计10个活动的男女童访客数避免N+1问题

问题描述

现有Laravel查询代码:

DB::table('visitors')
    ->join('event_visitor', 'visitors.id', '=', 'event_visitor.visitor_id')
    ->where('sex', 0)
    ->where('event_visitor.event_id', 1)
    ->count();

该代码用于统计活动ID为1的男性访客数量。

现需统计10个活动中男性、女性、儿童的访客数,最终要得到如下格式的数组:

$men = [100, 200, 300 ,400,500,600,700,800,900,1000];
$women = [100, 200, 300 ,400,500,600,700,800,900,1000];
$kids = [100, 200, 300 ,400,500,600,700,800,900,1000];

其中sex字段对应关系:

  • 0 = 男性(men)
  • 1 = 女性(women)
  • 2 = 儿童(kids)

要求在数据库层面实现,同时避免N+1查询问题。

解决方案

可以通过一次聚合查询,利用条件统计逻辑在数据库层面完成所有活动的分类统计,彻底规避N+1查询问题。

1. 编写聚合查询

使用Laravel查询构造器,通过CASE WHEN实现条件统计,按活动ID分组获取数据:

// 替换为实际需要统计的10个活动ID列表
$targetEventIds = [1,2,3,4,5,6,7,8,9,10];

$eventStats = DB::table('visitors')
    ->join('event_visitor', 'visitors.id', '=', 'event_visitor.visitor_id')
    ->whereIn('event_visitor.event_id', $targetEventIds)
    ->selectRaw('
        event_visitor.event_id,
        COUNT(CASE WHEN visitors.sex = 0 THEN 1 END) as men_count,
        COUNT(CASE WHEN visitors.sex = 1 THEN 1 END) as women_count,
        COUNT(CASE WHEN visitors.sex = 2 THEN 1 END) as kids_count
    ')
    ->groupBy('event_visitor.event_id')
    ->orderBy('event_visitor.event_id')
    ->get();

2. 转换为目标数组格式

将查询结果整理成要求的三个数组,保持活动ID的顺序一致性:

$men = [];
$women = [];
$kids = [];

foreach ($eventStats as $stat) {
    $men[] = $stat->men_count;
    $women[] = $stat->women_count;
    $kids[] = $stat->kids_count;
}

关键说明

  • 避免N+1:全程仅执行1次数据库查询,所有统计逻辑在数据库端完成,无需循环每个活动单独发起请求。
  • 条件统计原理:CASE WHEN会根据sex值判断是否计入统计,COUNT函数会自动忽略NULL值(不满足条件时CASE返回NULL),从而精准得到对应类别的访客数量。
  • 效率优化:whereIn限定了目标活动范围,避免查询无关数据;orderBy确保结果按活动ID排序,保证最终数组顺序与目标活动列表一致。

内容的提问来源于stack exchange,提问作者Abdoullah al-hajj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 22:05:19