- リンクを取得
- ×
- メール
- 他のアプリ
- リンクを取得
- ×
- メール
- 他のアプリ
エラーの概要
「Too many SOQL queries: 101」は、SalesforceにおけるSOQLクエリ実行数が1つのトランザクションで許容される上限(100回)を超えた場合に発生するランタイムエラーです。このエラーは、特に複雑なコードや無駄なクエリが多い処理で起きやすく、パフォーマンスの問題につながる可能性があります。
主な原因
- トリガー内でのSOQLクエリの乱用
- トリガーがレコード単位で動作しているため、レコード数に応じてクエリが繰り返し実行される。
- ループ内でのSOQLクエリの使用
- ループ処理の中でSOQLクエリを実行している場合、クエリ数が急増する。
- 呼び出しチェーン
- 複数のトリガーやクラスが連携して動作する場合、それぞれでSOQLクエリが発生する。
- 無駄なデータ取得
- 実際には必要のないデータを頻繁に取得している場合。
解決方法
- SOQLクエリのバルク化
-
SOQLクエリをループの外に移動し、複数のレコードをまとめて取得します。
NG例: ループ内でSOQLクエリを実行
// 全てのアカウントを取得するクエリ List<Account> accounts = [SELECT Id FROM Account]; // 各アカウントの連絡先を取得するループ for (Account acc : accounts) { // 各アカウントの連絡先を取得するクエリ List<Contact> contacts = [SELECT FirstName FROM Contact WHERE AccountId = :acc.Id]; // 連絡先の処理 for (Contact con : contacts) { System.debug('連絡先名: ' + con.FirstName); } }
改善例: 事前取得で関連データを効率化
// 全てのアカウントを取得するクエリ List<Account> accounts = [SELECT Id, ( SELECT FirstName FROM Contacts ) FROM Account]; for (Account acc : accounts) { for (Contact con : acc.Contacts) { // 連絡先の処理 System.debug('連絡先名: ' + con.FirstName); } }
大量のデータやループ内でSOQLクエリが多い場合、別のエラーが発生する可能性がございます。その場合、4番目の例をお勧めいたします。
-
- トリガーの実行制御
-
トリガーフレームワークを導入し、特定の条件下でのみトリガーを実行する。
フラグを使ったトリガー制御例
public class TriggerExecutionController { public static Boolean isTriggerExecutionAllowed = true; } // トリガー側 trigger AccountTrigger on Account (before insert, before update) { if (!TriggerExecutionController.isTriggerExecutionAllowed) { return; // 条件によりトリガーを終了 } // トリガー処理続行 }
-
- SOQLクエリの数をモニタリング
- デバッグログを利用して、クエリの実行状況を確認し、無駄なクエリを特定する。
- 関連データの事前取得
-
必要な関連データを一括取得し、繰り返しのクエリを避ける。
改善例: 事前取得で関連データを効率化
// マップ定義 Map<Id, LIST<Contact>> ContactsMap = new Map<Id, LIST<Contact>>(); // 全てのアカウントを取得するクエリ List<Account> accounts = [SELECT Id, ( SELECT FirstName FROM Contacts ) FROM Account]; // Contactデータを保存する for (Account acc : accounts) { if (!acc.Contacts.isEmpty()) { contactsMap.put(acc.Id, acc.Contacts);
} else { contactsMap.put(acc.Id, new List<Contact>()); // 連絡先が存在しない場合、空のリストを追加
} } // Contactデータを使用する for (Account acc : accounts) { LIST<Contact> ContactList= ContactsMap .get(acc.Id); }
-
その他のポイント
- デバッグログでガバナ制限をモニタリング
クエリの回数や実行タイミングをデバッグログで確認し、無駄な処理を特定します。 - Apex BatchやQueueableを活用
大量データを処理する際には、Apex BatchやQueueableを使用し、トランザクションを分割する設計を検討します。
コメント
コメントを投稿