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

优化Laravel Eloquent关联:减少员工月度排班查询次数

优化员工整月排班查询:减少数据库查询次数

当前实现遍历每月每天+每日17个时段,导致1000+次数据库查询,严重影响性能。核心优化思路是一次性拉取该员工整月的所有排班、缺勤数据到内存,再通过数组判断替代重复DB请求,具体实现如下:

第一步:批量获取整月数据

先从数据库一次性取出该员工当月的所有排班记录和缺勤日期,避免循环内查询:

// 确定当月的起止日期(假设$dates是当月日期数组,取首尾日期即可)
$startDate = reset($dates)->format('Y-m-d');
$endDate = end($dates)->format('Y-m-d');

// 1. 批量获取该员工当月所有排班记录
$allSubscribedUnits = $inst->instructor->subscriptionUnits()
    ->whereBetween('date', [$startDate, $endDate])
    ->select('date', 'from', 'to', 'unit_type')
    ->get()
    // 整理成按日期分组的数组,方便后续快速查找
    ->groupBy('date')
    ->map(function ($units) {
        // 把每个排班转成便于判断时段的结构
        return $units->map(function ($unit) {
            return [
                'from' => strtotime($unit->from),
                'to' => strtotime($unit->to),
                'unit_type' => $unit->unit_type
            ];
        })->toArray();
    })
    ->toArray();

// 2. 批量获取该员工当月所有缺勤日期(根据实际业务调整timings模型的查询逻辑)
$absentDates = $inst->instructor->timings()
    ->whereBetween('date', [$startDate, $endDate])
    ->pluck('date')
    ->map(function ($date) {
        return $date->format('Y-m-d');
    })
    ->toArray();

第二步:内存中处理排班逻辑

遍历日期和时段时,直接从内存数组中判断,不再发起DB请求:

$monthly = [];
$totalScheduledCount = 0;
$totalAvailableCount = 0;

foreach ($dates as $key => $today) {
    $todayStr = $today->format('Y-m-d');
    $daily = ['fullyAvailable']; // 索引0默认值
    $i = 1;
    $isAbsent = in_array($todayStr, $absentDates);

    // 当天缺勤直接标记,跳过时段遍历
    if ($isAbsent) {
        $daily[0] = 'fullyAbsent';
        $monthly[$key] = $daily;
        continue;
    }

    // 获取当天的排班记录(无则为空数组)
    $dailyUnits = $allSubscribedUnits[$todayStr] ?? [];

    for ($time = $opening_time; $time <= $closing_time; $time++) {
        $currentHourStart = strtotime($todayStr . " {$time}:00:00");
        $currentHourEnd = strtotime($todayStr . " " . ($time + 1) . ":00:00");
        $matchedUnit = null;

        // 检查当前时段是否有匹配的排班
        foreach ($dailyUnits as $unit) {
            // 时段重叠判断逻辑可根据实际业务调整
            if ($unit['from'] <= $currentHourStart && $unit['to'] >= $currentHourEnd) {
                $matchedUnit = $unit;
                break;
            }
        }

        if ($matchedUnit) {
            $daily[0] = 'fullyScheduled';
            $daily[$i] = $matchedUnit['unit_type'];
            $totalScheduledCount++;
        } else {
            $daily[$i] = 'available';
            $totalAvailableCount++;
        }
        $i++;
    }

    $monthly[$key] = $daily;
}

第三步:清理冗余方法

原模型中的hourlySubscribedUnit方法是循环内单次查询用的,优化后不再需要,可直接删除或注释。

关键优化点说明

  • 批量查询替代循环查询:把1000+次DB请求压缩到2次,大幅降低数据库连接开销
  • 数据结构优化:将查询结果按日期分组、转换时间戳,让内存判断更高效
  • 提前终止无效循环:当天缺勤直接跳过时段遍历,减少不必要的计算

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 12:30:56