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

Laravel中如何统计全年12个月的含体检服务就诊次数及总就诊次数?现有查询方案性能不佳求优化

优化Laravel全年就诊数据统计的方案

嘿,我来帮你解决这个性能问题!你的当前代码循环12次查询数据库,这就是耗时的根源——频繁的数据库往返开销太大了。咱们可以把12次查询合并成1次,一次性拿到全年12个月的统计数据,效率会高很多,同时还能补上总就诊次数的统计。

核心优化思路

通过一次数据库查询+按月份分组统计,替代循环多次查询,减少数据库交互次数;同时利用原生SQL函数完成两类数据的统计,再处理空月份的补全逻辑。

优化方案一:使用Eloquent结合原生SQL统计

这个方案用EXISTS子查询判断就诊是否关联体检服务,同时统计总次数和体检就诊次数:

$clinic = $user->Clinics->first();
$currentYear = date('Y');

// 一次性拉取全年所有有数据的月份统计
$monthlyStats = Visit::where('clinic_id', $clinic->id)
    ->whereYear('created_at', $currentYear)
    ->select([
        DB::raw('MONTH(created_at) as month'),
        DB::raw('COUNT(*) as total_visits'), // 当月总就诊次数
        DB::raw('SUM(CASE WHEN EXISTS (SELECT 1 FROM visit_check_ups WHERE visit_check_ups.visit_id = visits.id) THEN 1 ELSE 0 END) as checkup_visits') // 含体检的就诊次数
    ])
    ->groupBy('month')
    ->orderBy('month')
    ->get()
    ->keyBy('month');

// 初始化全年12个月的数组,确保没有数据的月份也显示0
$userPerMonth = [];
for ($i = 1; $i <= 12; $i++) {
    $stats = $monthlyStats->get($i, (object)['total_visits' => 0, 'checkup_visits' => 0]);
    $userPerMonth[$i] = [
        'total' => $stats->total_visits,
        'checkups' => $stats->checkup_visits
    ];
}

dump($userPerMonth);

优化方案二:使用Left Join统计

如果Visit和VisitCheckUps是一对多关联,也可以用leftJoin来实现,注意要加DISTINCT避免重复计数:

$monthlyStats = Visit::leftJoin('visit_check_ups', 'visits.id', '=', 'visit_check_ups.visit_id')
    ->where('clinic_id', $clinic->id)
    ->whereYear('created_at', $currentYear)
    ->select([
        DB::raw('MONTH(visits.created_at) as month'),
        DB::raw('COUNT(DISTINCT visits.id) as total_visits'), // 去重统计总就诊数
        DB::raw('COUNT(DISTINCT visit_check_ups.visit_id) as checkup_visits') // 统计关联体检的就诊数
    ])
    ->groupBy('month')
    ->orderBy('month')
    ->get()
    ->keyBy('month');

// 同样初始化12个月数据(和方案一一致)
$userPerMonth = [];
for ($i = 1; $i <= 12; $i++) {
    $stats = $monthlyStats->get($i, (object)['total_visits' => 0, 'checkup_visits' => 0]);
    $userPerMonth[$i] = [
        'total' => $stats->total_visits,
        'checkups' => $stats->checkup_visits
    ];
}

dump($userPerMonth);

额外性能优化:添加数据库索引

为了让查询更快,建议给相关字段添加索引,大幅提升过滤和关联查询的效率:

-- 给visits表添加clinic_id和created_at的联合索引
ALTER TABLE visits ADD INDEX idx_clinic_created (clinic_id, created_at);

-- 给visit_check_ups表添加visit_id的索引
ALTER TABLE visit_check_ups ADD INDEX idx_visit_id (visit_id);

为什么这个方案更快?

原来的代码执行了12次数据库查询,每次都要建立连接、执行SQL、返回结果;优化后只需要1次查询,所有统计逻辑在数据库端完成,减少了90%以上的数据库交互开销,数据量越大,性能提升越明显。

内容的提问来源于stack exchange,提问作者Mostafa Mahmoud

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 12:22:48