Database.Statefulインタフェースとは

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

ここで一つの疑問が

Statefulの機能はわかったものの、メンバ変数を更新しに行って、それが引き継がれるってことは、
1回目のバッチ→更新→2回目のバッチ→更新→・・・
って感じでシリアル(直列)に動いているんじゃない? って思いました。

パフォーマンス測定

気になるので、開発コンソール使って調べてみました。
対象データはいずれも100個。
バッチサイズとStatefulありなしを変えて実施してみました。

※ちなみに、開発コンソールのパフォーマンス測定については後日解説する予定です

バッチサイズ10、Statefulあり

バッチサイズ10Statefulなし

バッチサイズ1、Statefulあり

バッチサイズ1Statefulなし

バッチサイズ1、Statefulなし

バッチサイズ1Statefulあり

棒の長さが実行時間の長さになります。
結果は一目瞭然。やっぱり、Statefulにすると直列で動くため、実行時間が増えているのが分かりますね。
リファレンスとかに「パフォーマンス落ちるよ〜」とか書いてなかったが、やっぱり弊害はあるみたいです。
なので、Statefulは必要な時だけ使うようにしましょう。

まとめ

  • Database.Statefulは各プロセスのexecuteで更新したメンバ変数の値が引き継がれる
  • Database.Statefulを使用した場合、各バッチプロセスが直列で実施されるため、実行時間が長くなる

コメント

  1. より:

    こんにちは、林と申します。

    一点ご質問させて頂きたいですが、
    Database.Statefulあり、バッチサイズ10で20個のデータに対してバッチを実施する場合はExecuteが2回実施されますが、Summary変数がFOR分の中に実施されますので、
    結果はSummary=20のではないでしょうか?

    ご教授の程宜しくお願いいたします。

    • 管理人エスパー より:

      >林さん
      コメントありがとうございます。
      ご指摘の通り、Summary=20が正しいです。
      修正させていただきました。