Skip to content

[パフォーマンス] FrameConfig の事前ロードを表示対象フレームに絞り込む #2412

Description

@masaton0216

概要

ConnectFrame ミドルウェアで 全テーブル分の frame_configs を毎リクエストで読み込んでいるFrameConfig::get())。
UserPluginBase::setFrameConfigs() 側ではそれを Collection::where('frame_id', ...) でインメモリ絞り込みしており、
現状は N+1 クエリではないが、frame_configs テーブル行数にリニアにメモリ/転送量が比例する構造になっている。

将来的にサイト規模(フレーム数・設定数)が増えた場合のスケール対策としてリファクタしたい。

該当箇所

  • app/Http/Middleware/ConnectFrame.php L21-30
    public function handle($request, Closure $next)
    {
        // フレーム設定の共有
        \$frame_configs = FrameConfig::get();  // ← 全件ロード
        \$request->attributes->add(['frame_configs' => \$frame_configs]);
        return \$next(\$request);
    }
  • app/Plugins/User/UserPluginBase.php L1419-1427
    protected function setFrameConfigs()
    {
        if (empty(\$this->frame->id)) { return; }
        \$this->frame_configs = Request::get('frame_configs')->where('frame_id', \$this->frame->id);
    }

計測(ローカル開発DB / frame_configs 合計35行)

1ページ8フレーム想定、各20回の平均値。

方式 平均時間 DBから読む行数
現行(FrameConfig::get() 全件) 0.66ms 35行
改善(whereIn('frame_id', \$frame_ids)->get()->groupBy('frame_id') 0.67ms 12行(-66%)

小規模環境では時間差は出ないが、データ転送量・PHPメモリが対象フレーム分のみに限定される点が本改善の主効果。frame_configs テーブルが万行規模になった場合に時間差も顕在化する。

改善案

フレーム一覧(DefaultController::getFramesMain()layouts_info の共通エリアフレーム)の ID 群を求めた後にミドルウェアの代替処理として絞り込みロード、または現行ミドルウェアを廃止し DefaultController 側でフレーム取得後に一緒にロード→ request->attributes に map 形式で積む形が素直。

// 疑似コード
\$frame_ids = \$frames->pluck('id')->merge(\$common_frame_ids);
\$frame_configs_map = FrameConfig::whereIn('frame_id', \$frame_ids)
    ->get()
    ->groupBy('frame_id');
\$request->attributes->add(['frame_configs' => \$frame_configs_map]);

setFrameConfigs() 側は Request::get('frame_configs')->get(\$this->frame->id, collect()) に変更(Collection API は維持)。

注意点

  • UserPluginBase::refreshFrameConfigs() (L1432-1435) は個別に FrameConfig::where('frame_id', ...)->get() を呼ぶ実装で、更新直後の再取得用途。こちらはそのままで OK(呼び出しタイミングが限定的なため)。
  • Request::get('frame_configs') を直接参照するプラグインが無いか要確認(grep: DatabasesPlugin, FaqsPlugin, BlogsPlugin, MenusPlugin, CabinetsPlugin, PhotoalbumsPlugin, WhatsnewsPlugin 等が \$this->frame_configs 経由で参照)。API 互換を保てば影響なし。
  • API ルート(invokeGetJson など)で同ミドルウェアを通らない経路が無いか確認要。

チェックリスト

  • ConnectFrame ミドルウェアを撤去 or 絞り込み版に変更
  • DefaultController 側で対象フレーム ID を元にロード
  • setFrameConfigs() の取得 API 変更(Collection を維持)
  • 既存プラグインの表示リグレッションなし確認(Menus/Blogs/Databases/Faqs 等)
  • Before/After の行数・メモリ計測ログ添付

DB変更の有無

なし

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions