Upgrade to Pro — share decks privately, control downloads, hide ads and more …

フレームワークの「恩恵」と「制約」を見極めたバッチ処理の高速化

 フレームワークの「恩恵」と「制約」を見極めたバッチ処理の高速化

Avatar for Kazuya Umeki

Kazuya Umeki

April 11, 2026

More Decks by Kazuya Umeki

Other Decks in Technology

Transcript

  1. 概要 バッチ処理について 社員をグループに所属登録させるバッチ処理 日次データ同期バッチ CSV → DB CSVのレコード数: 約40,000件 社員数:

    4,000~5,000人、グループ数: 1000未満 実行時間: 約45分間 バッチ処理の速度改善と品質、保守性が求められていた CSV data “group_id”,”employee_no” “42”,”EMP_NO_001” “42,”EMP_NO_002” “105”,”EMP_NO_001” “105”,”EMP004” ... (約4万行)
  2. 概要 既存のバッチ処理のロジックについて ①. S3から取得したCSVファイルを1行ずつ読み込む ②. グループと社員がDB上に存在するか? No Yes 監査用ログ出力 グループに社員を所属登録

    るとプルがかかた CSV data “group_id”,”emp_no” “42”,”EMP_NO_001” “42,”EMP_NO_002” “105”,”EMP_NO_001” “105”,”EMP004” ... (約4万行)
  3. 課題点 何故45分かかる? Before N+1問題 + 洗い替え方式 $this→deleteAll(); // DELETE foreach

    ($records as $r) { $group = $groupRepo->load($r[‘g_id’]); // SELECT $emp = $userRepo→loadByEmpNo($r[‘emp_no’]); // SELECT if (!$group->getMember($emp)) { $group->addMember($emp); $group->save(); // INSERT / UPDATE } 4万行 × 毎行3回のDBアクセス = 約12万クエリ }
  4. 作戦 時短 x 保守性 x 工数 Option A Option B

    FWのAPIで書く 素のPHP+SQLで書く 遅い(45分) 保守性がネック Option C 計算は言語レイヤ 永続化はFW ✓ SELECTED
  5. Phase 1 メモ化とデータの正規化 After foreach // 1. ($records as メモ化

    $rows $gCache[$gID] ??= = $r) { [ $gRepo->load($r[‘gID’]); // 未ロードの場合のみDBへアクセス 42 ??= => [ 101 => true, 102 => true $empCache[$empNo] $empRepo→loadByEmpNo($r[‘empNo’]); 105 // 2. if ($gCache[$gID] => [ 103 => true ], 軽量ハッシュマップの構築 $empNo ] = && $empCache[$empNo]) { $emp_cache[$empNo]; グループ42 → ユーザー101, 102 を所属させたい $rows[$gID][$empNO] = TRUE; // スカラー値(TRUE)で } ], O(1) 探索用の構造を作る グループ105 → ユーザー103 を所属させたい } return [$rows, $gCache, $empCache]; // キャッシュデータ生成のみを行う関数
  6. Phase 2 差分更新を導入、不要なDELETEとINSERTを行わない。 After private function diff($currentIDs, $seletetedIDs): array {

    $add = $remove = []; // 所属登録処理を行う対象、脱退処理を行う対象を計算する(差分) foreach ($seletetedIDs as $id => $value) { // isset() のハッシュキー探索で O(1) で処理 if (!isset($currentIDs[$id])) { $add[] = $id; } } } foreach ($currentIDs as $id => $value) { if (!isset($seletetedIDs[$id])) { $remove[] = $id; } } return [$add, $remove];