Power AutomateのApply to eachを速くする|既定は順次実行、ネストすると並列が効かない
Power Automateで複数件のデータを処理しようとすると、必ず出てくるのが「それぞれに適用(Apply to each)」です。
動くには動くものの、件数が増えると急に遅くなります。実は既定では1件ずつ順番に処理しているだけで、設定ひとつで大きく変わります。この記事では、公式ドキュメントの実測データをもとに、速くする方法と効かない場面を整理します。
まず前提|配列を扱うときに必要になる
「それぞれに適用」は、配列(複数件のデータ)の各項目に対して処理を繰り返すアクションです。
公式のチュートリアルでも「それぞれに適用アクションには配列が必要」と説明されています。メールを10件取得する、SharePointの一覧を取得する——こうした操作の結果は配列で返るため、1件ずつ処理するにはこのアクションを挟みます。
追加は「新規ステップ」→「組み込み」→「それぞれに適用」を選び、動的コンテンツから対象の配列を指定します。
最大の改善点|既定は「順番に1件ずつ」
ここが最も効きます。
公式に明記されています。「各ループに適用するは、既定では順番に実行されます」
つまり10件あれば、1件目が終わってから2件目に進みます。1件に3秒かかるなら30秒です。
同時実行制御をオンにする
ループ内の項目に順序の依存がないなら、同時実行制御で複数を同時に処理できます。並行度は1から50の間で指定します。
公式が示している実測値です。
| 配列の長さ | 並列度 | ループの実行時間 |
|---|---|---|
| 4 | オフ | 21秒 |
| 4 | 2 | 11秒 |
| 4 | 4 | 6秒 |
| 4 | 6 | 6秒 |
オフの21秒が、並列度4で6秒になっています。3分の1以下です。
ただし上げれば速くなるわけではない
上の表をもう一度見てください。並列度を4から6に上げても、6秒のまま変わっていません。
配列が4件しかないので、それ以上並列にしても処理する相手がいないためです。並列度は「配列の件数」を超えても意味がありません。
公式も注意しています。「作業の分割、追加のスレッドのキューイング、呼び出されるエンドポイントからの遅延は、オーバーヘッドとなる」「数値を大きくしたとしても(50など)、必ずしも処理が速くなるわけではありません」
とりあえず50にする、は正解ではありません。件数と、呼び出し先が同時アクセスに耐えられるかで決まります。
変数を使うループでは並列にしない
注意が必要な組み合わせがあります。ループの中で変数に加算していくような処理です。
並列実行では処理の順序も完了のタイミングも保証されません。複数の繰り返しが同時に同じ変数を読み書きすると、集計結果が合わなくなります。
件数を数える、金額を合計する——こうした処理を含むループは、並列にしないでください。どうしても速くしたい場合は、変数を使わずに済む作り(配列に集めてから最後に集計するなど)へ変更してから並列化します。
処理できる件数には上限がある
公式の制限表に明記されています。
| 項目 | 制限 |
|---|---|
| 各配列項目に適用(処理できる配列項目の最大数) | Lowは5,000、それ以外は100,000 |
| 各同時実行に適用する(並列度) | 既定は1。1〜50に変更できる |
既定が1——これが「順番に1件ずつ」の正体です。設定を変えない限り並列にはなりません。
件数の上限を超えそうな場合、公式は「クエリアクションを使用して、大きい配列をフィルター処理できます」と案内しています。ループに入れる前に減らすのが原則です。
代替手段|SplitOnで分割する
あまり知られていない選択肢です。
配列を返すトリガーの場合、Foreachループを使うのではなく、SplitOnプロパティで配列アイテムを複数のワークフローインスタンスに分割できます。
1つのフロー実行で100件をループするのではなく、100件それぞれについてフローが起動する形になります。1件あたりの処理が独立しているなら、こちらのほうが素直です。
ただし上限が変わります。
- トリガーの同時実行がなし——Lowは5,000、それ以外は100,000
- トリガーの同時実行があり——100項目に減少
決定的な制約|ネストすると並列が効かない
これを知らないと、設定したのに速くならない理由が分かりません。
公式の記述です。「それぞれに適用アクションの同時実行制御は、クラウドフローの最上位レベルでのみ有効です。それぞれに適用アクションをネストすると、内側のアクションは常に順次実行されます」
つまりループの中のループには、同時実行制御が効きません。内側は必ず1件ずつです。
そもそも入れ子は避ける
公式は入れ子のループをアンチパターンとして明確に挙げています。理由は3つです。
- 実行時間が指数関数的に増える——それぞれ10回のループが2つなら、10×10=100回の反復になります
- 制限やクォータを超える可能性がある——反復回数や実行時間に上限があり、フローのエラーや調整(スロットリング)につながります
- パフォーマンスが低下する——反復ごとに処理能力とメモリを消費します
対策|1回の問い合わせでまとめて取る
公式が示す代替は、ループを重ねるのではなく、取得の時点で関連データもまとめて取るという考え方です。
Dataverseの例では、ODataのクエリ展開を使って親子のテーブルを1回のクエリで取得し、入れ子を1つのループに置き換えています。
- 展開クエリ——関連付けるルックアップ列を指定して、関連レコードを一度に取得する
- $select——関連テーブルから返す列を絞る
- 行のフィルター——条件を直接指定して、必要なレコードだけ取得する
「全部取ってからループで絞り込む」のをやめて、「必要なものだけ取る」に変える——これが根本的な解決です。
大量レコードの更新にループを使わない
公式はもうひとつ、はっきりした指針を示しています。
「データソースで数千のレコードを作成または更新する必要がある場合は、各レコードを順番に処理するためにFor eachループを使用しないでください」
代わりに使う手段
| 方法 | 内容 |
|---|---|
| バッチ操作 | 複数の操作を1つのHTTP要求にまとめる。1つ失敗しても他に影響しない |
| 並列処理 | バッチ非対応のサービス向け。最大50件を同時処理 |
| 一括操作(Dataverse) | 1つの操作として実行される。アクション数を大幅に減らせる |
バッチと一括の違い
混同されやすいので整理します。
- バッチ操作——1つの要求で送るが個別に処理される。件数が多いとオーバーヘッドと待機時間が増える
- 一括操作——1つの操作として実行される。要求全体が1アクションとして数えられるため効率が高い
公式の例では、Dataverseで100個の「行の作成」アクションの代わりに、CreateMultiple Web APIを使って1アクションで100レコードを処理しています。
無限ループに注意
別種の事故です。フローが自分自身をトリガーしてしまうケースがあります。
レコードが更新されたときに動くフローが、同じレコードを更新すると、永久に回り続けます。
Power Automateは保存時にこう警告します。「このフローのアクションは、無限トリガーループになる可能性があります」
止め方は2つ
- トリガー条件を使う——特定の条件を満たすときだけ実行する。「状態がまだ目的の値でない場合にのみ実行」といった形にします
- 終了アクションを使う——条件を検出したらフローを止める。安全装置として置きます
フローが止まったときの調べ方はフローが止まった時の対処にまとめています。
見落とされがちな点|スキップされたアクションもコスト
条件が満たされず実行されなかったアクションをスキップされたアクションと呼びます。
実行されなくてもリソースを消費し続けるため、パフォーマンスの問題を引き起こす可能性があると公式は指摘しています。
分岐の各枝に大量のアクションを並べると、これが積み上がります。対策は個別のアクションを並べるのではなく、分岐から子フローを呼び出すことです。メインのフローが簡素になり、保守もしやすくなります。
よくある質問
Q. Apply to eachが遅いです
既定は順番に1件ずつ処理しています。順序に依存がなければ同時実行制御をオンにしてください。公式の実測では、4件の配列で21秒が6秒になっています。
Q. 並列度はいくつにすべきですか?
1から50の範囲で指定できますが、大きくすれば速いわけではありません。配列の件数を超えても意味がなく、呼び出し先の遅延やスレッドのオーバーヘッドもあります。
Q. 同時実行制御をオンにしたのに速くなりません
ループがネストしていませんか。同時実行制御は最上位レベルでのみ有効で、入れ子の内側は常に順次実行されます。
Q. ループが二重になっています
公式がアンチパターンとしています。10回×10回で100回の反復になり、制限超過やエラーの原因になります。取得時にクエリ展開やフィルターを使い、1つのループにまとめてください。
Q. 数千件を更新したいです
ループを使わないでください。バッチ操作、並列処理(最大50件)、Dataverseなら一括操作を検討します。一括操作は1つの操作として実行されるためアクション数を大幅に削減できます。
Q. 何件まで処理できますか?
公式の制限ではLowは5,000件、それ以外は100,000件です。超えそうな場合は、ループに入れる前にクエリアクションでフィルターして減らしてください。
Q. ループの中で件数を数えたら合いません
並列実行にしていませんか。並列では順序も完了タイミングも保証されないため、同じ変数を複数の繰り返しが読み書きして結果が狂います。集計を含むループは並列にしないでください。
Q. フローが勝手に繰り返し動きます
無限ループの可能性があります。フローが更新したレコードで自分自身がトリガーされていないか確認し、トリガー条件か終了アクションで止めてください。
まとめ
- 「それぞれに適用」は既定で順番に1件ずつ処理している
- 同時実行制御をオンにすると並列処理できる。並行度は1〜50
- 公式の実測では4件の配列でオフ21秒→並列度4で6秒
- ただし上げれば速いわけではない。件数を超えた並列度は無意味で、オーバーヘッドもある
- 同時実行制御は最上位レベルのみ有効。ネストした内側は必ず順次実行
- 入れ子のループはアンチパターン。10×10=100回に膨れ、制限超過を招く
- 対策はクエリ展開やフィルターで必要なものだけ取ること
- 数千件の更新にループは使わない。バッチ操作・並列処理・一括操作を使う
- 処理できる配列は Low 5,000/それ以外 100,000。超えそうならループ前にフィルターで絞る
- 変数に加算するループは並列にしない。順序が保証されず集計が狂う
- 配列を返すトリガーならSplitOnで分割する手もある(同時実行ありなら上限100件)
- スキップされたアクションもリソースを消費する。分岐からは子フローを呼ぶ
参考・出典
- 並列実行と並行処理によるフローの最適化|Microsoft Learn――「それぞれに適用」が既定で順次実行されること、並行度を1〜50で設定できること、配列4件での実測値(オフ21秒/並列度2で11秒/4で6秒/6で6秒)、数値を大きくしても必ずしも速くならない理由、同時実行制御が最上位レベルでのみ有効でネストした内側は常に順次実行されること、スキップされたアクションがリソースを消費すること
- アンチ パターンを回避する|Microsoft Learn――入れ子のFor eachループを避ける理由(10×10=100回の指数関数的増加、制限やクォータの超過、パフォーマンス低下)、ODataクエリ展開による代替、数千件の更新にFor eachを使わないこと、バッチ操作と一括操作の違い、無限ループの警告と回避策
- 自動化フロー、スケジュールされたフロー、インスタント フローの制限事項|Microsoft Learn――「各配列項目に適用」の上限(Lowは5,000、それ以外は100,000)とクエリアクションによるフィルター処理の案内、「各同時実行に適用する」の既定値1と1〜50への変更、SplitOnによる配列の分割と同時実行がオンの場合に上限が100項目へ減少すること
- それぞれに適用アクションを使用してアイテムの一覧を定期的に処理する|Microsoft Learn――「それぞれに適用」アクションには配列が必要であること、追加の手順







