ガバナ制限を回避した大量データの一括更新にも便利 Batch Apexの使い方

Salesforceのレコードのクレンジングやアーカイブなど、複雑な夜間バッチ実行では、大量のデータを処理することになります。

通常、SFDCでのクエリ実行にはガバナ制限が適用され、大量のデータを処理する場合には、特に気を付けなければいけません。

そこで、Batch Apexという仕組みを使うと、制限が少し上がるほか、処理を細かい単位に分けて実行できるため、ガバナ制限を回避下ロジックを記述しやすくなります。最大の実行可能なレコード件数は5千万件となります。

また、Batch Apexは、あらかじめ登録して定期的に時刻起動するよう設定することもできますので、文字通り夜間バッチとして利用することもできます。

Apex Bachの構成

バッチを作成するには、Database.Batchable Interfaceを実装する必要があります。実装するには、以下の3つのメソッドの記述が必要です。

①start method

global (Database.QueryLocator | Iterable<sObject>) start(Database.BatchableContext bc) {}

このメソッドで、処理対象のレコードを取得します。select文でレコードを抽出し、QueryLocaterかIterable型のリストにすれば、そのリストに対して処理が行われます。

②execute method

global void execute(Database.BatchableContext BC, list<p>){}

このメソッドで、実際の処理が行われます。startメソッドで取得したのオブジェクトの型のListと、バッチ実行のコンテキストを引数とします。

③finish method

global void finish(Database.BatchableContext BC){}

このメソッド内でバッチの後処理を行えます。メールを送信したり、後続のバッチを起動したりすることに利用できます。バッチコンテキストから起動されたバッチのIdを取得することもできます。

AsyncApexJob a = [SELECT Id, Status, NumberOfErrors, JobItemsProcessed,
    TotalJobItems, CreatedBy.Email
    FROM AsyncApexJob WHERE Id =
    :BC.getJobId()];

Apex Batchクラスの作成

では、シンプルなクラスを書いてみます。取引先担当者の項目を更新するバッチです。

public class ContactUpdateBatch implements Database.Batchable<sObject>, Database.Stateful {
 
    private Integer recordCount {get; set;}
 
    public ContactUpdateBatch() {
 
        this.recordCount = 0;
    }
 
    public Database.QueryLocator start(Database.BatchableContext BC) {
        String query = 'SELECT Id FROM Contact';
        return Database.getQueryLocator(query);
    }
 
    public void execute(Database.BatchableContext BC, List<sObject> scope) {
        for (Contact cont : scope) {
            cont.Lastname = 'Cont_Changed';
            this.recordCount++;
 
        }
        update scope;
    }
 
    public void finish(Database.BatchableContext BC) {
 
    }
 
}

上記クラスを実行するにはいくつか方法があります。

簡単な方法は、開発者コンソールから以下の文を実行する方法です。テストしたり、ワンショットの作業として行うにはこの方法がいいでしょう。executeBatch()に渡す引数のうち、後ろの200はバッチサイズで、一回の処理で実行する件数で、抽出されたレコード件数は、このバッチサイズで分割されて処理されます。最大2000を指定できます。この単位でガバナのカウントがリセットされるので、ガバナ制限に引っかかりにくいわけですね。

ただし、1つのバッチの実行時間は10分以内である必要がありますので、気を付けましょう。

ContactUpdateBatch batch = new ContactUpdateBatch();
Database.executeBatch(batch, 200);

すると、実行結果のログが以下のように表示されます。

もうひとつは、バッチとしてスケジューラに登録する方法です。

global class Scheduled_batch implements Schedulable {
 
  private final Integer BATCH_SIZE = 200;
 
  global void execute(SchedulableContext ctx) {
      ContactUpdateBatch batch = new ContactUpdateBatch();
      Database.executeBatch(batch, BATCH_SIZE);
  }
}

上記のように、Schedulableインターフェースを実装したクラスを作成して、スケジューラ登録します。登録方法は2通りあります。

①設定画面から登録

ビルド –> 開発 –> Apexクラス –> Apexをスケジュール

②プログラム的にスケジューラに登録

ただし、上記の方法だと、1時間単位でしか実行時間の指定ができないため、もっと細かい単位での指定は、プログラム的に行う必要があります。下記ソースを開発者コンソールから実行することで、登録が可能です。

Scheduled_batch sb = new Scheduled_batch();
String sch = '0 20 10 ? * MON-FRI';
String jobID = system.schedule('Job名', sch, sb);

上記の’0 20 10 ? * MON-FRI’はクローン式と呼ばれる記述方法で、スケジュールの記述を行います。この例は「月曜から金曜まで毎日10時20分に実行」という意味ですが、詳しい記述方法はSalesforceのこのページを参照すると良いでしょう。

なお、クローン式は、左から、秒、分、時、日、月、曜日、年を表しています(年は省略可)

上記が、登録後の結果で、「ジョブ –> スケジュール済みジョブ」から確認できます。