Database.Statefulとは
Database.Statefulはexecute内で更新されたメンバ変数の値を保持することができます。
開発者ガイドにも説明があります。
実際に使う
使用する場合はバッチクラスと一緒に使います。
インタフェースにDatabase.Batchableと共に指定します。
ソース上に出てくるBook__cはNameしか持たないカスタムオブジェクト。
カスタムオブジェクトでなくても、Accountとかで良いんだけど、実験でレコードの追加と削除を頻繁にやるのでオブジェクトは別にしました。
BookBatch.cls
public class BookBatch implements Database.Batchable<sObject>, Database.Stateful{
// Statefulで値を確認するための変数
public integer Summary;
public BookBatch(){
Summary = 0;
}
public Database.QueryLocator start(Database.BatchableContext BC){
return Database.getQueryLocator('Select Id From Book__c');
}
public void execute(Database.BatchableContext BC, List<sObject> scope){
for(sObject s : scope){
// execute内でメンバ変数を更新
Summary = Summary + 1;
}
}
public void finish(Database.BatchableContext BC){
System.debug(Summary);
}
}
実行結果
バッチサイズ10で20個のデータに対しバッチ実行
>実行結果記載誤りのため修正しました
Database.Stateful あり:Summary=20
Database.Stateful なし:Summary=0
Database.Stateful なし:Summary=0
ここで一つの疑問が
Statefulの機能はわかったものの、メンバ変数を更新しに行って、それが引き継がれるってことは、
1回目のバッチ→更新→2回目のバッチ→更新→・・・
って感じでシリアル(直列)に動いているんじゃない? って思いました。
パフォーマンス測定
気になるので、開発コンソール使って調べてみました。
対象データはいずれも100個。
バッチサイズとStatefulありなしを変えて実施してみました。
※ちなみに、開発コンソールのパフォーマンス測定については後日解説する予定です
バッチサイズ10、Statefulあり
バッチサイズ1、Statefulあり
バッチサイズ1、Statefulなし
棒の長さが実行時間の長さになります。
結果は一目瞭然。やっぱり、Statefulにすると直列で動くため、実行時間が増えているのが分かりますね。
リファレンスとかに「パフォーマンス落ちるよ〜」とか書いてなかったが、やっぱり弊害はあるみたいです。
なので、Statefulは必要な時だけ使うようにしましょう。
まとめ
- Database.Statefulは各プロセスのexecuteで更新したメンバ変数の値が引き継がれる
- Database.Statefulを使用した場合、各バッチプロセスが直列で実施されるため、実行時間が長くなる
コメント
こんにちは、林と申します。
一点ご質問させて頂きたいですが、
Database.Statefulあり、バッチサイズ10で20個のデータに対してバッチを実施する場合はExecuteが2回実施されますが、Summary変数がFOR分の中に実施されますので、
結果はSummary=20のではないでしょうか?
ご教授の程宜しくお願いいたします。
>林さん
コメントありがとうございます。
ご指摘の通り、Summary=20が正しいです。
修正させていただきました。