Salesforceでデータのセレクト結果を返すメソッドに2種類あり、どういうときに使い分けた方が良いのかが「あやふや」だったので調査したことをまとめておきます。
Database.Query()とDatabase.getQueryLocator()の違い
Database.Query()・・・このメソッドは、実行時に動的に生成したSOQLで検索を行いたいときに使用します。最大50,000件のレコードを取得することができます。もし、BatchApexなどで使用しても、50,000件以上処理することは出来ません。以下のような例でSOQLを動的に組み立てられます。
String fieldName = ',Name,Email';
String dynQuery = 'select Id ' + fieldName + ' From Account';
Database.query(dynQuery);
Database.getQueryLocator()・・・ApexBatchとVisualForceページで使用されることが多いですが、使う場所によって扱える件数が異なります。ApexBatchのなかで使用すると、最大5,000万件までのデータを扱うことができます。ただし、一回でまとめて取ってくるわけではなく、指定したバッチサイズの件数(デフォルト200件)ごとに取ってきて、それを繰り返しで処理します。データベースでいうところのカーソルのフェッチみたいな仕組みをイメージすると良いかもしれません。一回で取得する件数を抑えながらも、最終的には大量のデータを扱うことができるので、Batch Apexの処理内で使われるのは納得ですよね。
もうひとつの使いどころは、StandardSetControllerを使ったVisualForcePageで、主にページング処理を実現するのに使用されます。ここで使用するときには、取得できる最大の件数は10,000件に制限されます。
VisualForcePageでの使用イメージ
ここで、VisualForcePageのページング処理での使用イメージを載せておきます。
StandardSetControllerのコンストラクタは以下の2種類を持っています。
前者はsObjectのリストを渡す形式、後者はQueryLocatorを渡す形式です。
sObjectのリストを渡す形式
List<account> accountList = [SELECT Name FROM Account LIMIT 20];
ApexPages.StandardSetController ssc = new ApexPages.StandardSetController(accountList);
QueryLocatorを渡す形式
ApexPages.StandardSetController ssc =
new ApexPages.StandardSetController(Database.getQueryLocator([SELECT Name,CloseDate FROM Opportunity]));
さて、StandardSetController のインスタンス化の際に受け取ることの出来るレコード数は10,000件に制限されています。ただし10,000件以上のレコードがHitして、コンストラクタに渡ったときの振る舞いは両者で異なります。
前者のsObjectのリストを渡したときには10,000件でレコードが切り捨てられ、エラーは出ません。しかし、後者のQueryLocatorの場合は、10,001件以上だとエラーになります。(Too many query locator rows)。
なお、ApexではStandardSetControllerを使用することで簡単にページネーション機能を実装することができますが、大量な件数を表示する場合は、ページのプロパティの中に、readOnly=trueを設定します。これで、通常は1000件までのレコード表示が50,000件まで行えるようになります。(でも、上で述べたように、QueryLocatorの場合は、10,001件以上だとエラーになります。)
Database.query() | Database.getQueryLocator() |
---|---|
50,000レコードまで扱える | 10,000レコードまで扱える |
Batch Apexで使ったとしたら、レコード数は50,000レコードまでに制限される | Batch Apexで使ったとしたら、レコード数は5千万レコードまで扱える |
VFページでread onlyを使わないのであればこちらを使う。 | VFページでread onlyを使うのであればこちらを使う。 |
のようになると思います。