0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Part 12: ガバナ制限の超過を防ぐエラーハンドリング

Posted at

Part 12: ガバナ制限 (Governor Limits) の超過を防ぐエラーハンドリング

前回は プラットフォームイベントとスケジュールバッチのエラーハンドリング を解説しました。
今回は Salesforce のガバナ制限 (Governor Limits) に関するエラーを防ぐ方法 について詳しく解説します。


1. ガバナ制限とは?

Salesforce は マルチテナント環境 で動作するため、1 つの組織がシステムリソースを独占しないように 「ガバナ制限 (Governor Limits)」 を設定しています。

例えば:

  • SOQL クエリ制限 → 1 トランザクションで 100 件まで
  • DML ステートメント制限 → 1 トランザクションで 150 件まで
  • CPU タイム制限 → 同期処理は最大 10 秒、非同期処理は最大 60 秒まで
  • ヒープサイズ制限 → 6MB (標準)、非同期処理は 12MB
  • コールアウト制限 → 1 回のトランザクションで最大 120 秒

これらの制限を超えると LimitException が発生し、処理が中断されます。


2. LimitException の発生を防ぐ方法

2.1. SOQL クエリ制限 (System.QueryException)

SOQL クエリの実行回数が 1 トランザクションあたり 100 件 を超えると QueryException が発生します。

NG 例: ループ内で SOQL クエリを実行

for (Account acc : Trigger.new) {
    Contact c = [SELECT Id FROM Contact WHERE AccountId = :acc.Id LIMIT 1];
}

→ ガバナ制限エラー (System.LimitException: Too many SOQL queries: 101) が発生!

OK 例: SOQL を 1 回だけ実行

Map<Id, Contact> contactMap = new Map<Id, Contact>();
for (Contact c : [SELECT Id, AccountId FROM Contact WHERE AccountId IN :Trigger.newMap.keySet()]) {
    contactMap.put(c.AccountId, c);
}

// ループ内で SOQL を実行しない
for (Account acc : Trigger.new) {
    Contact c = contactMap.get(acc.Id);
}

→ SOQL クエリを 1 回だけ実行し、マップを活用することで制限を回避!

適用ケース:
トリガー (Trigger) やバッチ処理で SOQL を実行する際、クエリ回数を削減したい場合


2.2. DML 制限 (System.DmlException)

DML (insert, update, delete, upsert) の実行回数が 1 トランザクションあたり 150 件 を超えると DmlException が発生します。

NG 例: ループ内で DML を実行

for (Account acc : accounts) {
    update acc;
}

→ ガバナ制限エラー (System.LimitException: Too many DML statements: 151) が発生!

OK 例: DML を 1 回だけ実行

update accounts;

→ DML を 1 回でまとめて実行 (バルク処理) することで制限を回避!

適用ケース:
多数のレコードを更新する際に DML 制限を回避したい場合


2.3. CPU タイム制限 (System.LimitException)

同期処理では 最大 10 秒、非同期処理では 最大 60 秒 を超えると LimitException が発生します。

NG 例: 非効率な処理

for (Integer i = 0; i < 1000000; i++) {
    System.debug('処理中: ' + i);
}

→ 不要なループが多すぎると、CPU タイム制限に引っかかる!

OK 例: 必要な処理だけ実行

for (Integer i = 0; i < 1000000; i+=100000) { // 10万ごとにログ出力
    System.debug('処理中: ' + i);
}

→ 不要な処理を削減し、CPU タイムを節約!

適用ケース:
大量データ処理を行う場合に CPU タイム制限を回避したい場合


2.4. ヒープサイズ制限 (System.LimitException)

ヒープサイズの制限は 同期処理で 6MB、非同期処理で 12MB
大量データを扱う場合、ヒープサイズを超えると LimitException が発生します。

NG 例: 大量データをすべてメモリに保持

List<Account> allAccounts = [SELECT Id, Name FROM Account];

→ 全レコードを取得すると、ヒープサイズ制限を超える可能性あり!

OK 例: バッチ処理を活用

Database.QueryLocator query = Database.getQueryLocator(
    'SELECT Id, Name FROM Account'
);

Database.QueryLocator を使うと、レコードを一括取得せずに処理できる!

適用ケース:
大量のレコードを扱う際にヒープサイズ制限を回避したい場合


2.5. コールアウト制限 (System.CalloutException)

コールアウト (外部 API 呼び出し) の制限は 1 トランザクションあたり 120 秒

NG 例: ループ内で API を呼び出す

for (Account acc : accounts) {
    HttpRequest req = new HttpRequest();
    req.setEndpoint('https://api.example.com/data');
    req.setMethod('GET');
    HttpResponse res = new Http().send(req);
}

→ ガバナ制限エラー (System.CalloutException: Callout loop detected) が発生!

OK 例: コールアウトをバッチ処理に分割

// コールアウトをバッチ処理で実行
public class CalloutBatch implements Database.Batchable<SObject>, Database.AllowsCallouts {
    public Iterable<SObject> start(Database.BatchableContext bc) {
        return [SELECT Id FROM Account LIMIT 100];
    }

    public void execute(Database.BatchableContext bc, List<SObject> scope) {
        HttpRequest req = new HttpRequest();
        req.setEndpoint('https://api.example.com/data');
        req.setMethod('GET');
        HttpResponse res = new Http().send(req);
    }

    public void finish(Database.BatchableContext bc) {}
}

Database.AllowsCallouts を使ってバッチ処理でコールアウト!

適用ケース:
API コールアウトを効率的に処理し、制限を回避したい場合


まとめ

今回は ガバナ制限 (Governor Limits) を超えないためのエラーハンドリング を解説しました。

SOQL クエリ制限

  • ループ内で SOQL を実行せず、マップを活用する

DML 制限

  • DML を 1 回だけ実行 (バルク処理)

CPU タイム制限

  • 不要なループや処理を減らす

ヒープサイズ制限

  • バッチ処理 (Database.QueryLocator) を活用

コールアウト制限

  • バッチ処理 (Database.AllowsCallouts) を使う

次の Part 13 では、例外をトラブルシューティングする方法 (デバッグ手法) について解説します!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?