[salesforce]SOQLでガバナ制限を超える方法1 – SOQL query for loop

By |2月 3, 2010|salesforce, |


Force.com上で開発を進めていると、いつか必ずぶつかるのがガバナ制限との戦い。そんなガバナ制限の1つであるSOQLに関する制限を超える方法の1つである「SOQL query for loop」について解説します。

SOQLで取得できるレコード数に関するガバナ制限

SQOL処理を使うことで、特定のオブジェクト内のレコードを検索してその結果レコードリストを得ることができます。しかしこの結果リストとして一度のSOQL文で得ることが出来るレコード数には厳しい制限があり、「トリガ内からは1000レコード」「Testコードからは500レコード」「その他からは10000レコード」となっています。

これくらいのレコード数は簡単に超えてしまいそうなもので、例えば以下のようなSOQLを実行してaccountオブジェクト全体を検索した場合、

[php]
Account[] accts = [SELECT id FROM account];
[/php]

accountオブジェクトにガバナ制限を超える大量のレコードが保存されていると、ガバナ制限を超えてしまってランタイムエラーになります。

それでもガバナ制限を超えるレコードをSOQLで扱いたい場合はあります。そんな時の回避策の1つに「SOQL query for loop」というものがあります。

SOQL query for loopの書き方

SOQL query for loopとは、forループ文の条件式の部分にSOQL文を書く方法を指します。これには2通りの方法があり、SOQLの結果を単一レコードで受け取るか、複数レコードのリストで受け取るか、を選ぶことが出来ます。

SOQLで取得したレコードセットに対してDML処理をしない場合の例

[php]
for (Account a : [SELECT id, name FROM account
WHERE name LIKE ‘Acme’]) {
//色々コードを書く
}
[/php]

SOQLで取得したレコードセットに対してDML処理をしたい場合の例

[php]
for (List<Account> accts : [SELECT id, name FROM account
WHERE name LIKE ‘Acme’]) {
// 色々コードを書く
update accts;
}
[/php]

後者の場合は、forループの中でacctsという配列の中にSQOLで取得したレコードセットが200レコードずつ格納されます。forループ内でDML処理をする時はその200レコードずつ処理を行うことになります。

例えば実例はこんな感じ。

[php]
public void massUpdate() {
for (List<Contact> contacts:
[Select FirstName, LastName From Contact]) {
for(Contact c : contacts) {
if (c.FirstName == ‘Barbara’ &&
c.LastName == ‘Gordon’) {c.LastName = ‘Wayne’;
}
}
update contacts;
}
}
[/php]

Contactオブジェクトのレコードを検索して、その結果レコードが大量の場合も一括更新できるように書いた例です。3行目のfor文内のSQOLでContactオブジェクトの大量のレコードが取得されてそれが200レコードごとの配列に分割されてcontactsという配列に格納されます。その後4行目のfor文でその200レコードが格納されているレコードセット内の各レコードの各フィールド値を書き換えて、9行目でDML処理を実行してレコードの更新を完了。この処理を繰り返すことで全レコードに対して更新処理が行えることになります。

ただし

このように大量レコードのDML処理を行う場合は、SOQL query for loopを使うのは非推奨となっており、その代わりに最近リリースされた機能であるBatch APEXが推奨されています。これはまた後日。

参考:Working with Very Large SOQL Queries