この文章は Salesforce 機械翻訳システムを使用して翻訳されました。詳細はこちらをご参照ください。
英語に切り替える

Newer Version Available

This content describes an older version of this product. View Latest

非常に大きい SOQL クエリの処理

SOQL クエリがヒープサイズの制限を超える多数の sObject を返し、エラーが生じることがあります。問題を解決するには、代わりに SOQL クエリ for ループを使用します。query および queryMore への内部コールが使用されるため、レコードの複数の一括処理が可能になります。

たとえば、結果が大きすぎる場合、次の構文で実行時例外が発生します。

1Account[] accts = [SELECT Id FROM Account];

代わりに、次の例のいずれかで SOQL クエリ for ループを使用します。

1// Use this format if you are not executing DML statements 
2// within the for loop
3for (Account a : [SELECT Id, Name FROM Account 
4                  WHERE Name LIKE 'Acme%']) {
5    // Your code without DML statements here
6}
7
8// Use this format for efficiency if you are executing DML statements 
9// within the for loop
10for (List<Account> accts : [SELECT Id, Name FROM Account
11                            WHERE Name LIKE 'Acme%']) {
12    // Your code here
13    update accts;
14}

次の例は、レコードの一括更新に使用する SOQL クエリ for ループを示します。指定された条件と一致する姓名を持つ取引先責任者のレコードで、取引先責任者の姓を変更するとします。

1public void massUpdate() {
2    for (List<Contact> contacts:
3      [SELECT FirstName, LastName FROM Contact]) {
4        for(Contact c : contacts) {
5            if (c.FirstName == 'Barbara' &&
6              c.LastName == 'Gordon') {
7                c.LastName = 'Wayne';
8            }
9        }
10        update contacts;
11    }
12}

for ループで SOQL クエリを使用する代わりに、Apex の一括処理を使用してレコードを一括更新すると、ガバナ制限に達するリスクが最小限に抑えられます。

詳細は、「SOQL For ループ」を参照してください。

より効率的な SOQL クエリ

最高のパフォーマンスを得るためには、特にトリガ内のクエリに対しては、セレクティブ SOQL クエリを使用する必要があります。実行時間が長くなるのを避けるために、システムはセレクティブ以外の SOQL クエリを終了できます。200,000 件を超えるレコードを含むオブジェクトに対してトリガでセレクティブではないクエリを使用すると、エラーメッセージが表示されます。このエラーを回避するには、必ずセレクティブクエリを使用します。

セレクティブ SOQL クエリ条件
  • クエリ検索条件の 1 つがインデックス付き項目にあり、そのクエリ検索条件によって結果となる行数がシステム定義のしきい値より少なくなる場合、そのクエリはセレクティブです。SOQL クエリのパフォーマンスは、WHERE 句に使用される 2 つ以上の検索条件がその条件を満たす場合に改善されます。
  • 選択度しきい値は、初めの 100 万件のレコードの 10%、それ以降のレコードの 5% 未満の、最大 333,333 件です。インデックス付き標準項目であるクエリ検索条件がある場合など一部の状況では、しきい値が高くなる場合があります。また、選択度しきい値は変化します。
セレクティブ SOQL クエリのカスタムインデックスに関する考慮事項
  • 次の項目はデフォルトでインデックスが付けられます。
    • 主キー (Id、Name、OwnerId 項目)
    • 外部キー (参照関係または主従関係項目)
    • 監査日付 (CreatedDate、SystemModstamp 項目)
    • RecordType 項目 (これらの項目を備えたすべての標準オブジェクトにインデックス付け)
    • 外部 ID または一意としてマークされたカスタム項目
  • 頻繁に実行されるクエリのパフォーマンスがインデックスによって向上することが Salesforce オプティマイザによって確認された場合は、デフォルトでインデックスが付けられない項目に自動的にインデックスが付けられます。
  • Salesforce サポートは、お客様からの要求に応じてカスタムインデックスを追加できます。
  • カスタムインデックスは、複数選択リスト、マルチ通貨組織の通貨項目、ロングテキスト項目、一部の数式項目、およびバイナリ項目 (blob 型の項目、ファイル、または暗号化されたテキスト項目) では作成できません。Salesforce には定期的に新しいデータ型 (一般に複雑なデータ型) が追加されますが、これらのデータ型の項目は常にカスタムインデックス付けが可能なわけではありません。
  • 選択リスト項目での TEXT 関数の呼び出しを含む数式項目に、カスタムインデックスを作成することはできません。
  • 通常、次の場合はカスタムインデックスが使用されません。
    • クエリされた値がシステム定義のしきい値を超える場合
    • 検索条件の演算子が、NOT EQUAL TO (または !=)、NOT CONTAINSNOT STARTS WITH などの否定演算子である場合
    • 検索条件に CONTAINS 演算子が使用され、スキャンされる行数が 333,333 を超える場合。CONTAINS 演算子にはインデックスの完全スキャンが必要です。このしきい値は変化します。
    • 空の値と比較している場合 (Name != '')

    ただし、カスタムインデックスを使用できない複雑なシナリオは他にもあります。ここに記載された条件以外のシナリオがある場合、またはセレクティブではないクエリに関するヘルプが必要な場合は、Salesforce カスタマーサポートにお問い合わせください。

セレクティブ SOQL クエリの例
大きなオブジェクトでのクエリがセレクティブであるかどうかを理解するために、いくつかのクエリを解析することにします。これらのクエリについては、Account sObject に 20 万件を超えるレコードがあると想定します。これらのレコードには、理論削除されたレコード (まだごみ箱に残っているレコード) も含まれます。
クエリ 1:
1SELECT Id FROM Account WHERE Id IN (<list of account IDs>)

WHERE 句は、インデックス付き項目 (ID) に使用されています。SELECT COUNT() FROM Account WHERE Id IN (<list of account IDs>) が選択度しきい値より少ないレコードを返す場合は、Id へのインデックスが使用されます。このインデックスは通常、ID のリストに少数のレコードのみが含まれる場合に使用されます。

クエリ 2:
1SELECT Id FROM Account WHERE Name != ''

名前はインデックス付きですが (主キー) Account は大きなオブジェクトであるため、この検索条件はほとんどのレコードを返すことから、クエリは非セレクティブとなります。

クエリ 3:
1SELECT Id FROM Account WHERE Name != '' AND CustomField__c = 'ValueA'

ここでは、各検索条件が個別に考慮された場合にセレクティブであるかどうかを確認する必要があります。前の例で確認したように、最初の検索条件はセレクティブではありません。そのため、2 つ目の検索条件を重点的に確認することにします。SELECT COUNT() FROM Account WHERE CustomField__c = 'ValueA' が返すレコードの件数が選択度しきい値より少なく、かつ CustomField__c がインデックス付きである場合、このクエリはセレクティブです。