优化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
相关产品推荐
相关产品推荐

