SOQL結果のDML +制限
レコードのリストを照会し、変更を加えて、同じものを更新しようとしています。ここには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番目のアプローチでヒープサイズを節約できます。
回答
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を超えるレコードを更新する準備をする必要があります。