Salesforceガバナ制限エラーの原因と直し方【Apex現場の対処パターン】 

※この記事にはアフィリエイトリンクを含みます。

ガバナ制限エラーが出たら、まずここを疑え

Salesforce開発で System.LimitException: Too many SOQL queries: 101Too many DML statements: 151 が出たら、ガバナ制限に引っかかっています。

主な上限値はこれです。

種類同期非同期
SOQLクエリ回数100回200回
DML(insert/update/delete)回数150回150回
DMLで処理できる総レコード数10,000件10,000件
CPU実行時間10,000ms60,000ms

これに引っかかると、こうなります。

  • 途中まで処理したのに、例外で止まって『全部ロールバック』
  • ユーザーはエラー画面で作業中断、手戻り発生
  • 直しは「設計からやり直し」になりがち(地味に痛い)

この記事は「どのエラーが出たか」「なぜ起きるか」「どう直すか」を、現場でよくある事故パターン順に整理します。

ガバナ制限とは?

ガバナ制限は、Salesforceがプラットフォーム全体の安定性を保つために設けている『1トランザクションあたりの資源使用上限』です。

要は、みんなで使う大きな遊び場で、一人が使いすぎて全体を止めないためのお約束です。

(ブランコを1人で独占したら、他の人が遊べないのと同じ)

まず押さえる:よく事故る代表3つ

ここだけ先に覚えておけば、事故の8割は避けられます。

1) SOQL(検索)の回数・件数

  • 1トランザクションで実行できるSOQL回数に上限がある
  • 1回のSOQLで返せる件数にも上限がある(大量データで事故)

2) DML(登録・更新・削除)の回数・件数

  • insert / update / delete の実行回数に上限がある
  • 1回で処理できるレコード数にも上限がある

3) CPU時間(Apexの実行時間)

  • 1トランザクション内でのApex実行時間に上限がある
  • 「処理が重い」「ループが多い」「無駄が多い」で刺さる

※上限値は実行条件(同期/非同期など)で変わるので、数字は"暗記"よりも「どれが危ないか」を優先してください。

典型的にやらかす:ループの中でSOQL/DML

ガバナ制限に抵触しやすいコード(悪い例)です。

for (Account a : [SELECT Id, Industry FROM Account LIMIT 150]) {  
    if (a.Industry == 'Technology') {  
        a.Is_Tech__c = true;  
    }  
    // ループ内でDML  
    update a;  
}

これ、見た目はシンプルなんですが、「ループ=回数が増える場所」にDMLを置いているのがアウトです。

データが増えた瞬間に上限へ一直線になります。

技術的なポイント
・ループの中にSOQL/DMLを置くと、処理件数に比例して回数が増える
・同期トランザクションではSOQL100回、DML150回が上限
・データが少ない開発環境では通っても、本番データ量で突然死するパターンが多い

直し方:まとめて取る/まとめて更新する(基本形)

ガバナ制限に抵触しにくいコード(良い例)です。

List<Account> accountList = [  
    SELECT Id, Industry, Is_Tech__c  
    FROM Account  
    LIMIT 150  
];  

List<Account> accountsToUpdate = new List<Account>();  

for (Account a : accountList) {  
    if (a.Industry == 'Technology') {  
        a.Is_Tech__c = true;  
        accountsToUpdate.add(a);  
    }  
}  

if (!accountsToUpdate.isEmpty()) {  
    update accountsToUpdate;  
}

ポイントは2つだけです。

  • 『検索(SOQL)は1回でまとめる』
  • 『更新(DML)は1回でまとめる』

これがいわゆる「一括処理(バルク処理)」の基本です。

実務ポイント
・SOQLとDMLは必ずループの外に出す。これだけで事故の大半は防げる
・更新対象はListに積んでおき、ループ後に1回updateするのが基本形
・Triggerでも同じ考え方。Trigger.newをそのままループに渡してDMLは絶対NG

「じゃあ何が問題なの?」を現場目線で整理

ガバナ制限に抵触すると、単にエラーになるだけじゃなく、周りに被害が出ます。

1) トランザクションが失敗してロールバック

例外が出た瞬間に処理が止まり、そのトランザクション内の更新が『全部なかったことになります』。

結果として「更新されたはずがされてない」事故が起きます。

2) ユーザー体験が悪化する

ユーザーはエラー画面で止まり、業務が中断します。

「何回もやり直す」「別の人に依頼し直す」みたいな手戻りが出ます。

3) パフォーマンスと運用コストが上がる

制限に当たらないように処理を分割したり、非同期に逃がしたりで、設計が複雑になります。

テストと障害調査も難しくなります。

4) スケールしない

少量データでは動くのに、データが増えると死ぬ。

このタイプは、後から直すほど痛いです。

事故を減らす「現場のチェックリスト」

実装レビューや自分のセルフチェックにそのまま使えます。

  • ループの中で SOQL / DML / callout をしていないか
  • 取得対象は本当に必要な項目だけか(不要項目の取りすぎで重くなる)
  • 更新はまとめて1回でできないか
  • 大量データが来た時の動き(件数増加)を想像できているか
  • 重い処理を同期でやっていないか(必要なら非同期へ)
次に読む
ガバナ制限に当たったときの原因特定の手順だけまとめました。
デバッグログの読み方とLimit確認の基本を整理しています。
ガバナ制限に当たったときの調べ方(デバッグログ/Limitの見方)を読む →

まとめ:ガバナ制限は「チーム全体の事故」を防ぐためのルール

ガバナ制限に抵触すると、トランザクション失敗・ロールバック・ユーザー停止が起きます。

だからこそ、開発では「ループの中に危険物(SOQL/DML)を置かない」「まとめて処理する」を基本にして、事故を未然に防ぐのが大事です。

昔の自分は「守ればいいルール」くらいの理解でしたが、立場が変わって見直すと、これって『自分だけの問題じゃなくて、チーム全体に迷惑が波及するルール』なんですよね。

学び直し、大事です。

では、また次の記事で。

次の記事へ

次に読む
ガバナ制限に当たったときの原因特定の手順だけまとめました。
デバッグログの読み方とLimit確認の基本を整理しています。
ガバナ制限に当たったときの調べ方(デバッグログ/Limitの見方)を読む →
おすすめの記事