💻 システム開発

SCALE_CRM_リスト性能_根本原因とHubSpot対比

最終更新 2026年06月24日 / 31_システム開発部/_SCALE_CRM_リスト性能_根本原因とHubSpot対比.md

SCALE CRM 架電リストが重い — 根本原因の洗い出しとHubSpot対比

大串FB(2026-06-24)「リストがとにかく重くて開けないってクレーム。HubSpotはどれだけ顧客データあってもスムーズ。この差は何か洗い出して」への回答。

実測(本番D1 scale-lead-prod・2026-06-24)

項目 実測値
最大案件 mnpg72 call_rows 6,134行 / 5.92MB
1行の列数 20列超(約12万セル)
旧chunked blob(残骸) +7.92MB / 19チャンク(per-rowと二重保存・読まれていないがD1のゴミ)
他案件 moz6qooo63107=948行 / mp87cnkuj9pk4=410行 / momb5hxfan3je=319行

取得(loadRows core.js:3542)=j.rows を全件一括取得→全行 JSON.parse。ページングなし。
描画(_renderCallListBody calllist_core.js)=first 200 sync + rest in idle chunks(CHUNK=400) だが最終的に全行をDOM化(仮想スクロール無し=grep 0件)
絞り込み(allCalls.filter(c=>!c.deleted_at) 786行ほか)=検索・ソート・フィルタは全部クライアントで全件走査。
同期=30秒ポーリング(per-row diffPush)/アイドル2分。

重さの根本原因(影響度順)

# 重大度 原因 効く所
1 🔴致命的 全行をDOM化(仮想スクロール無し) 約12万DOM要素 開けない・固まる の主因
2 🔴致命的 全件一括DL 5.92MB+6,134回JSON.parse・ページング無し 起動の壁
3 🟠大 検索/ソート/絞り込みがクライアント全件走査 操作のたびに重い
4 🟡中 30秒ポーリングの全体同期+複数タブ輻輳 常時負荷
5 🟡中 起動時に全行を正規化する _migrateCallListV3 初回render
6 🟡中 旧chunked blob 7.92MBの二重保存(移行の不完全) D1容量・掃除対象
7 🟢小 per-row化でlocalStorage保持を廃止→リロードで5.92MB再DL(v86でスナップ即表示は導入済) リロード時

HubSpotとの差 = 機能ではなく「設計思想」

レイヤー SCALE CRM(現状・O(n)) HubSpot等(O(1))
取得 全6,134行を毎回まるごと 初回50行だけ+スクロールで追加
描画 全行をDOM化(12万要素) 見える約30行だけDOM(仮想スクロール)
絞り込み ブラウザで全件総当たり サーバDBがインデックスで絞って結果だけ返す
同期 30秒ポーリングで全体 差分/購読push

本質:SCALEは「全部を持ってきて全部を描く」ので行数に比例して重くなり、6千行で限界。HubSpotは「見える分だけ」なので何万件でも仕事量が一定。これは最適化の巧拙ではなく設計の世代差。

なぜ過去の対策(v87/88)で直らなかったか

2026-05のv87「描画分割(CHUNK 200→400)」・v88「行高さ32px固定+1行省略」はカクつきは減らしたが「全行をDOMに置く」設計は不変。だから行数増で必ず再発する対症療法だった。基準点でも「第3弾=仮想スクロールは専用セッションで慎重に」と保留してきた。

本丸(直すなら効果順)

  1. 仮想スクロール(描画をO(1)化) ← 単独で体感激変・最優先。選択/編集/同期poll/統計/ソートとの整合テストが必須。
  2. サーバーサイドページング(初回50行→スクロールで追加・取得をO(1)化)。
  3. サーバー側で検索/絞り込み/ソート(D1にインデックス・絞ってから返す)。
  4. (おまけ・軽い)旧chunked blob 7.92MB掃除proj_*_call_list_chunk_* 削除)。

①だけで「重くて開けない」はほぼ解消。架電リストの中核改修ゆえ、テスト環境検証→慎重投入が前提。

関連