SOQL結果のDML +制限

Sep 01 2020

レコードのリストを照会し、変更を加えて、同じものを更新しようとしています。ここには2つのアプローチがあります。

アプローチ1:

 List<Account> listOfAccToUpdate=new List<Account>();
for(Account acc: [SELECT field1 FROM Account WHERE Rba__c=true]){
    acc.field1=true;
    listOfAccToUpdate.add(acc);
}
update listOfAccToUpdate;

アプローチ2:

List<Account> listOfAccToUpdate=new List<Account>();
for(List<Account> accList: [SELECT field1 FROM Account WHERE Rba__c=true]){
    for(Account acc: accList){
        acc.field1=true;
    }
    if(listOfAccToUpdate.size()+accList.size()<=10000){
        listOfAccToUpdate.addAll(accList);
    }
    else{
        update listOfAccToUpdate;
        listOfAccToUpdate.clear();
        listOfAccToUpdate.addAll(accList)
    }
    
    
}

質問-クエリが10,000を超えるレコードを返すかどうかわからないため、アプローチ2の方が優れていますか。また、構文的にはループでDMLを実行していますが、2番目のアプローチでヒープサイズを節約できます。

回答

4 sfdcfox Sep 01 2020 at 09:50

10Kレコードの制限がありますので、トランザクションごと、一度に10,000レコードに自分自身を制限している場合、それは問題ではありません。まだ10,000行に制限されています。したがって、戦略は「10000行を超える場合は、キュー可能またはバッチ可能なメソッドにジャンプする」のようにする必要があります。

さらに、ガバナーの制限に違反する前に、クエリは50,000行に制限されます(これも、クエリごとではなく、トランザクションごとに)。これは、オブジェクトごとに多くのフィールドをクエリしない限り、通常はヒープスペースに収まります。代わりに、DML操作ごとに1,000行など、より小さなサイズに移動したい。

一般に、大きなデータスキューが心配な場合は、バッチ可能またはキュー可能に起動します。それ以外の場合は、違いについて心配する必要はありません。for-record-listメソッドの方が少し効率的ですが、さらに高速なのは、レコードをコピーせずに最初のメソッドを使用することです。

 List<Account> listOfAccToUpdate=[SELECT field1 FROM Account WHERE Rba__c=true];
for(Account acc: listOfAccToUpdate){
    acc.field1=true;
}
update listOfAccToUpdate;

このループは、ヒープの過度の再割り当てを回避するため、最高のパフォーマンス特性を備えています。パフォーマンス関連の質問については、この回答、この回答、この回答、この回答、この回答(私のものではない)、この質問(これも私のものではない)、この質問(より最適化、私のものではない)、およびその他のパフォーマンスの質問を参照してください。

あなたはいくつかの矛盾した答えに気付くかもしれません。Salesforceの正確なパフォーマンス特性は時間の経過とともに変化する傾向があるため、独自のテストを行うことをお勧めしますが、さらに重要なこととして、マイクロ最適化について心配する必要はありません。長期的には実際には問題にならないか、最適化される可能性があります。将来のリリースで。

この回答から取り除く必要がある唯一のことは、10kの制限はハード制限であるため、可能性が心配な場合は、キュー可能またはバッチ可能に分岐して10kを超えるレコードを更新する準備をする必要があります。