プロジェクト

全般

プロフィール

サポート #2207

未完了
アデ 廣僚

在庫管理の年度別集計をリファクタリング

サポート #2207: 在庫管理の年度別集計をリファクタリング

アルドリノ デフリン さんが10ヶ月前に追加. 9日前に更新.

ステータス:
フィードバック
優先度:
通常
担当者:
開始日:
2026/01/13
期日:
進捗率:

50%

予定工数:
起票元ID:
自動起票の種別:
却下理由:

説明

指示内容

問題

  • 管理画面アクセス
  • Livewire が state を評価
  • Filament が summarizer を呼ぶ
  • sum() が 重い SQL を発行
  • DB が計算
  • PHP が待つ
  • Nginx が待つ
  • fastcgi_read_timeout 超過
  • upstream timed out

やるべき修正(優先度順)

1. sum() を view 描画から外せ

Blade / Livewire / Summarizer 内で集計 ❌
Controller / Page クラスの mount() で 1回だけ 実行

public int $totalSales;

public function mount()
{
    $this->totalSales = Order::where(...)->sum('amount');
}

2. キャッシュしろ(必須)

$this->totalSales = Cache::remember(
    "sales_sum_fy_{$year}",
    3600,
    fn () => Order::where(...)->sum('amount')
);

3. 年度別集計テーブルを作れ

daily / monthly / yearly summary
cron or queue で更新
在庫・売上系は必ず事前集計。

レベル1:インクリメンタル集計(最優先)
考え方
データが「増減した瞬間」にだけ計算する
「見るとき」は読むだけ
具体例(売上合計)

❌ 毎回

SELECT SUM(amount) FROM orders WHERE ...

✅ 書き込み時

DB::table('sales_summary')
  ->where('year', $year)
  ->increment('total_amount', $amount);

ファイル

最適化案.md (25.2 KB) 最適化案.md アルドリノ デフリン, 2026/01/13 19:35

アデ アルドリノ デフリン さんが9日前に更新 操作 #1

  • ステータス を 新規 から 進行中 に変更
  • 進捗率 を 0 から 30 に変更

アデ アルドリノ デフリン さんが9日前に更新 操作 #2

  • ステータス を 進行中 から フィードバック に変更
  • 担当者 を アルドリノ デフリン から 廣瀬 僚一 に変更
  • 進捗率 を 30 から 50 に変更

対応内容

# 内容 対象
1 インデックスを 3 つ追加 sales_slips.date、sales_slip_items.product_id、purchases (product_id, date)
2 在庫数を全商品分まとめて集計 在庫確認画面、在庫確認エクスポート
3 月別売上の条件を日付範囲に変更 ダッシュボード(今月の売上・月別グラフ)
  • 1. インデックス: 計測した結果、売上集計の結合列(client_id・sales_rep_id・area_id など)へのインデックスは、MySQL が遅い結合方法を選ぶことで一部の集計画面が 10〜25ms 遅くなったため、追加していません。効果のあった 3 つに限定しています。
  • 2. 在庫数の一括集計: Product::withStockFigures() を追加し、全商品分の 4 項目を 2 つの集計サブクエリでまとめて取得するように変更しました。表示・出力される値は従来と同じです。
  • 3. ダッシュボード: whereYear()・whereMonth() ではインデックスが使われないため、whereBetween()(月初〜月末)に変更しました。

計測結果(ローカル環境)

対象 変更前 変更後
在庫確認エクスポート(全 170 商品) 1,388ms・1,193 クエリ 15ms・3 クエリ
在庫確認エクスポート(商品区分で絞り込み) 739ms・731 クエリ 8ms・3 クエリ
在庫確認画面(10 件表示) 324ms・228 クエリ 約 110ms・14 クエリ
在庫確認(100 件分) 約 730ms・約 700 クエリ 25ms・1 クエリ
年度別売上集計(SQL 時間) 81ms 38ms
ダッシュボードのウィジェット 9〜24ms 3〜8ms
その他の売上集計 7 画面 35〜125ms 変化なし(±5ms)

値の確認:

  • 全 175 商品 × 4 項目で、新しい集計と従来の計算結果が完全に一致
  • 在庫確認エクスポート・ダッシュボードの値が変更前と一致(エクスポートで文字列だった数値 3 セルが、数値として出力されるようになった点のみ変化)
  • 管理画面の全 35 ページの表示と、自動テストが成功

指示内容への対応状況

指示 対応 理由
1. sum() を view 描画から外し、mount() で 1 回だけ実行 一部対応 実際に描画中に大量の sum() を実行していたのは在庫確認画面だったため、そこを一括集計に変更。売上集計画面の Summarizer は高速で、mount() に移すとフィルタと合計が連動しなくなるため変更せず
2. キャッシュ 対応なし 集計は十分に高速になり、キャッシュすると伝票保存直後に古い合計が表示されるおそれがあるため
3. 年度別集計テーブル/インクリメンタル集計 対応なし 現在のデータ量(明細約 6,700 件)では不要で、集計値のずれのリスクが大きいため。なお現在庫数(products.stock)は、すでに仕入・売上の保存時に増減する方式になっている

データ量が大きく増えた場合(目安として現在の 10 倍以上)は、2・3 を再検討します。

他の形式にエクスポート: PDF Atom