並列ワーカーを増やしたのに処理が遅くなった、あるいは不安定になった——そういう状況で真っ先に疑うべきは、ボトルネックが「容量の問題」ではなく「通り道の渋滞」になっている可能性だ。
この2つは別の病気であり、治療法が逆になる。容量不足なら並列化は効く。だが渋滞が原因なら、並列を増やすほど状況が悪化する。どちらの病気かを見分けることが、チューニングの出発点になる。
規模を倍にしたら、裏処理が6倍遅くなった
実機での観測を出発点として示す。
処理対象レコードを5万件から10万件——規模を2倍——に増やした。書き込み自体はほぼ線形にスケールした。ところが、書き込み後に走る裏処理(プラグイン・同期処理)の1件あたりの処理時間が約6倍に膨らんだ。
レコード数は2倍なのに、1件あたりのコストが6倍。これは容量不足で起きる線形のスケール超過とは異なる動きだ。「通り道」に何かが詰まって、ピタゴラスイッチ的に連鎖悪化していた。
環境前提の確認:チューニング対象はリクエスト制限のあるプラットフォームで動く同期処理。スペックアップで解決する問題ではない。
2種類の遅さの病気——型Aと型B
処理が遅い原因には2種類あり、対策が逆になる。
| 観点 | 型A(容量不足) | 型B(直列渋滞) |
|---|---|---|
| 症状 | エラーではじかれる・OOM・タイムアウト | じわじわ遅くなる・不安定 |
| 限界の形 | 硬い壁(急激に落ちる) | なめらかな遅延爆発(利用率が上がるにつれ非線形に悪化) |
| 並列を増やすと | 速くなる | 遅くなる |
| 診断の手がかり | ログにリソース不足の記録が残る | ログは正常・ただしキューの待ち時間が長い |
| 対策の方向 | スケールアップ / スケールアウト | 1単位の仕事量を絞る・通り道を太くする・時間分散 |
冒頭の6倍膨張は型Bの典型だ。エラーは出ていない。ただ、ある1本の共有資源への書き込み競合がひたすら積み上がっていた。
待ち行列の経済——利用率が上がると待ち時間は非線形に爆発する
型Bの「なめらかな遅延爆発」の数学的な構造は、待ち行列理論で説明できる。
コーヒーショップを想像してほしい。レジは1台、客は次々と来る。客が少ないうちは注文してすぐ受け取れる。客が増えてレジの処理能力の80%くらいに達しても、多少の列はできるが許容範囲だ。ところが90%を超えたあたりから、列が急激に伸び始める。99%に近づくと、列は事実上無限に長くなる。
これはコーヒーショップだけの話ではなく、1つの共有資源に複数のワーカーが書き込みを競合させる構造すべてに当てはまる。
Kleinrock の教科書(Queueing Systems, Volume 1: Theory, 1975年, Wiley)が示す M/M/1 キューイングモデルの公式がその理由だ。
W ∝ 1 ÷ (1 − ρ)
W が待ち時間、ρ(ロー)が利用率(到着率 ÷ 処理率)。利用率が1に近づくほど、待ち時間は際限なく膨らむ。
| 利用率 ρ | 待ち時間の倍数(基準比) |
|---|---|
| 50% | 約2倍 |
| 80% | 約5倍 |
| 90% | 約10倍 |
| 99% | 約100倍 |
並列ワーカーを増やすということは、1本の共有資源への到着率 λ を上げることだ。λ が上がれば ρ が上がり、待ち時間は非線形に爆発する。「並列を増やしたのに遅くなった」は、数学的な必然になる。
なぜDBのトランザクションログが「1本の直列資源」なのか
バッチ処理や同期処理の文脈で、この「1本の共有資源」の実体になりやすいのがDBのトランザクションログだ。
SQL Server・PostgreSQL・MySQL InnoDB、いずれの公式ドキュメントも、トランザクションログがシーケンシャルな1本のストリームであることを明記している。
SQL Server(Microsoft Learn, 2026年時点の仕様)では、ログレコードはLSN(Log Sequence Number:ログの連番)で識別される単一ストリームに順序付きで書き込まれる。物理的にはVLF(仮想ログファイル)に分割されるが、論理的には1本のシーケンシャルな流れだ。
PostgreSQL(公式ドキュメント)は WAL(Write-Ahead Log:書き込み先行ログ)についてこう記述している。
“The WAL file is written sequentially, and so the cost of syncing the WAL is much less than the cost of flushing the data pages.”
MySQL InnoDB も Redo Log をシーケンシャルに物理ファイルへ書き込む。コミット時には Binary Log への順序付き記録と InnoDB コミットの2段階を経る。
3つのDBエンジンで構造は共通している。コミット処理は「1本の通り道を、1つずつ順番に通過する作業」だ。並列ワーカーが増えるほど、この1本への書き込み競合が激化し、利用率 ρ が跳ね上がる。結果は待ち行列の公式が示す通りだ。
Dataverse / Power Platform でも同じ構造が現れる
特定製品の固有問題ではなく、構造的な普遍性として理解してほしいが、Microsoft Dataverse も同じメカニズムが現れる場所の一例として挙げられる。
ExecuteMultipleRequest(従来型のバルクAPI)は最大1,000リクエスト/バッチで、各リクエストは個別のDBトランザクション内で実行される(Microsoft Learn, 2026年時点)。CreateMultiple / UpdateMultiple(新型バルクAPI)ではTargetsにEntityCollectionをまとめて渡せるが、プラグイン登録時のペイロード上限は116.85 MBだ。プラットフォームレベルでは5分間100,000リクエストという制限もある。
Dataverse のトランザクションログ実装の詳細を公式が明文化したドキュメントは現時点で見当たらない。ただし、個別DBトランザクションとして処理されるという仕様は、シリアルなログ書き込みを示唆する間接証拠として解釈できる——この点は推論の域であり、要検証だ。
いずれにせよ、「並列リクエストを増やしても処理が速くならない・逆に不安定になる」という症状がDataverse上で出た場合、型Bの診断チェックリストを適用する価値がある。
型Bに効く対策3選
型Bと診断できたなら、対策の方向は3つに絞られる。
対策1:1単位の仕事量を絞る(バッチサイズの縮小)
なぜ効くか。1トランザクションに含めるレコード数を減らすと、1回のコミットが占有する時間が短くなる。利用率 ρ が下がり、待ち時間が非線形に改善する。
具体的には、大量レコードを一括処理する設計から、小さいバッチを繰り返す設計に切り替える。Dataverse のようにプラットフォームが動的に推奨並列度(DOP: Degree of Parallelism)を返す仕組みがある場合は、その推奨値に従うことが最初の一手になる。
対策2:直列の通り道を太くする(ログ書き込みのIOPS強化)
なぜ効くか。μ(処理率)を上げることで、同じ λ でも ρ を下げられる。待ち行列の公式の分母を大きくする発想だ。
トランザクションログのディスクIOPSを強化する(HDDからSSD、SSDからNVMeへ)、ログとデータを別ドライブに分離する、DBのパーティション設計を見直すといった手段が該当する。ハードウェア的な解決策が可能な環境では、最も効果が出やすい。
対策3:負荷を時間で分散する(バッチ時間帯の分散・スロットリング制御)
なぜ効くか。λ(到着率)のピークを平準化することで、瞬間的な ρ の上昇を抑える。1本の通り道を同時に叩く量を制御する発想だ。
大量処理を深夜バッチに分散する、リクエスト間にウェイトを挟む、優先度の高い処理とバッチ処理の時間帯を分離するといった方法が実装上の選択肢になる。スロットリング制限があるプラットフォームでは、制限値を逆算して送信ペースを設計する。
型B診断のチェックフロー:
1. エラーが出ているか?
→ Yes: 型A(容量不足)を先に疑う
→ No: 次へ
2. 並列ワーカーを増やすほど1件あたりの処理時間が延びているか?
→ Yes: 型B(直列渋滞)の可能性が高い
3. ログ書き込みやコミット処理のIOウェイトが増加しているか?
→ Yes: 型B確定。対策1〜3を検討する
まとめ
「並列を増やしたのに遅くなった」の原因が直列共有資源の渋滞にある場合、並列化はむしろ逆効果だ。型Aと型Bを見分け、型Bなら「1単位を絞る・通り道を太くする・時間分散」の3方向で対応する。
次の一歩:まず症状がエラーなのか・じわじわ遅延なのかを確認する。じわじわ遅延ならログのIOウェイト計測に進む。計測なしのチューニングは的を外しやすい。
関連記事:バルクAPIを使っても律速が消えない理由——受け手が1件ずつ処理していないか確認する(本記事の「送る側」と対になる「受け手側」の構造問題を扱う)
→ Power Platform・Dataverse での設計判断の全体像:[Microsoft Power Platform 設計判断の地図](リンク予定)