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?

ApexのDML制限を踏まえたベストプラクティス

Last updated at Posted at 2025-02-25

Salesforceの DML(データ操作言語) には制限があり、適切に処理しないと ガバナ制限違反 でエラーが発生します。
今回は、DMLの制限と、それを考慮したベストプラクティスとアンチパターン を具体的なコードとともに整理しました。


DMLの主な制限

  1. 実行されるDMLステートメントの合計数

    • 1回のトランザクションで150回までINSERT, UPDATE, DELETE, UPSERT, MERGE, UNDELETE が実行可能。
  2. DMLステートメントの結果として処理されるレコードの合計数

    • 1回のトランザクションで10,000件まで のレコードを処理可能。
  3. ヒープメモリの合計サイズ

    • 6MB(同期処理)または12MB(非同期処理)まで
    • メモリを使いすぎると System.LimitException: Apex heap size too large エラーが発生。

1. ❌ アンチパターン: DMLステートメントを個別実行

✅ 理由

  • DML制限(最大150回)にすぐ到達 してしまう。
  • 処理速度が遅くなる(DMLは1回ごとにデータベースアクセスが発生するため)。

📌 ❌ 悪い例(DMLステートメントを個別実行)

public void updateContacts() {
    List<Contact> contacts = [SELECT Id, LastName FROM Contact];
    
    for (Contact con : contacts) {
        con.LastName = 'Updated Name';
        update con; // ❌ ループ内でDMLを実行(150件超えるとエラー)
    }
}

問題点

  • コンタクトが150件以上あるとエラー(DML制限違反)
  • データベースへのアクセス回数が多く、パフォーマンスが低下

✅ 良い例(バッチ処理を使用)

public void updateContactsBatch() {
    List<Contact> contacts = [SELECT Id, LastName FROM Contact];

    for (Contact con : contacts) {
        con.LastName = 'Updated Name';
    }

    update contacts; // ✅ 1回のDMLでまとめて更新
}

DMLを1回にまとめることで、制限回避&高速化!


2. ✅ 原則:DMLステートメントのためのバッチデータ

✅ 理由

  • ループ内のDMLを削減し、ガバナ制限を回避 する。
  • データをコレクションに集め、DMLを一括で実行することで高速化

📌 ❌ 悪い例(ループ内でDMLを実行)

public void insertAccountsIndividually() {
    for (Integer i = 0; i < 200; i++) {
        Account acc = new Account(Name = 'Test Account ' + i);
        insert acc; // ❌ ループごとにDMLが発生(150件超えるとエラー)
    }
}

問題点

  • 150回以上のDML実行でエラー (System.LimitException: Too many DML statements)
  • データベースへの負荷が大きく、処理速度が低下

📌 ✅ 良い例(リストを使ってDMLをバッチ処理)

public void insertAccountsBatch() {
    List<Account> accountsToInsert = new List<Account>();

    for (Integer i = 0; i < 200; i++) {
        accountsToInsert.add(new Account(Name = 'Test Account ' + i));
    }

    insert accountsToInsert; // ✅ 1回のDMLで一括処理
}

データをリストにまとめ、DMLを1回で実行することで、パフォーマンス向上&ガバナ制限回避!


3. ✅ 原則:SOQL for ループを使用して200件ごとのバッチを作成

✅ 理由

  • ヒープサイズ制限を回避する(データを少量ずつ処理)。
  • SOQLの結果を自動的にバッチ処理できる

📌 ❌ 悪い例(全レコードを一度に取得)

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

for (Account acc : accounts) {
    System.debug(acc.Name);
}

問題点

  • 取得したデータが多すぎると、ヒープサイズ制限(6MB)に達する可能性あり

📌 ✅ 良い例(SOQL for ループで200件ずつ処理)

for (Account acc : [SELECT Id, Name FROM Account]) {
    System.debug(acc.Name); // ✅ 少量ずつ処理し、メモリ使用量を抑える
}

SOQL for ループを使うと、Salesforceが自動的にレコードをバッチ処理し、ヒープサイズを抑える!


📌 ✅ 大量データを安全に更新するバッチ処理

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

for (Account acc : [SELECT Id, Name FROM Account]) {
    acc.Name = acc.Name + ' Updated';
    accountsToUpdate.add(acc);

    if (accountsToUpdate.size() == 200) {
        update accountsToUpdate; // ✅ 200件ごとにDML実行
        accountsToUpdate.clear();
    }
}

// 残りのレコードを処理
if (!accountsToUpdate.isEmpty()) {
    update accountsToUpdate;
}

200件ごとに処理することで、ガバナ制限を回避&パフォーマンス向上!


🎯 まとめ

項目 ❌ 悪い例 ✅ 良い例
DMLをループ内で実行 update con; をループ内で実行 リストにまとめて1回のDMLで処理
DMLのバッチ処理 insert acc; を200回実行 200件ごとにDMLを実行
SOQL for ループを活用 List<Account> accounts = [SOQL] で全取得 for (record : [SOQL]) を使用
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?