SOQLクエリのパフォーマンスチューニング
by Tetsuo Ajima on 9月 17, 2010 at 09:44 午後
最初に確認すべきポイント
まず最初に確認すべきポイントは、SOQLクエリの検索条件です。
SOQLクエリの検索条件にインデックス化された項目が含まれているかどうかを確認してください。
[Select Field1__c, Field2__c, Field3__c From CustomObject__c Where Field1__c = :value]
上記の場合、データベースにて Field1__c のインデックスが作成されている必要があります。
インデックスの作成
データベース内部で項目のインデックスを作成させるには、項目の編集画面にて「外部 ID」チェックボックスをONにします。
「外部ID」項目はUpsert処理のキーに利用する項目ですが、「外部ID」に指定された項目はデータベース内部でインデックスが作成されるので、パフォーマンスチューニングのためにこの設定をするという使い方が可能です。
「外部ID」項目は、1つのオブジェクトに対してデフォルトで3つまで指定できます。
ただし、インデックス化された項目を検索条件にした場合の絞り込みがデータ全体の1/10以下になるようなデータ分布でないと、インデックス作成の効果は無いことに注意してください。
(追記: データ全体の件数が100万件以上になる場合は1/20以下に絞り込めないとインデックスとしての効果がありません。)
また、Id項目やName項目、監査日付項目(例: LastModifiedDate)などはデフォルトでインデックス化されています。IdやNameを検索条件にした検索は高いパフォーマンスを期待できます。
(追記: 標準項目のインデックスは、データ全体の30%以下に絞り込めること、かつ絞り込んだ件数が33万3千件以下である必要があります。カスタム項目のインデックスは、絞り込んだ件数が100万件以下である必要があります。)
検索条件にインデックス化された項目が複数含まれる場合
検索条件にインデックス化された項目が複数含まれる場合は、Force.comプラットフォームのクエリオプティマイザが実行計画を立てる際に、効果が高いと判断された項目が優先して使用されます。
データ件数が多い場合
検索対象のオブジェクトに格納されているデータ全体の件数が多いと検索のパフォーマンスに影響します。
筆者の経験では、Apexトリガなら10万件、Visualforceコントローラやレポート・リストビューの実行であれば100万件を超えるような場合に、検索条件となる項目のインデックスが作成されているかどうかに注意すべきです。とは言え、利用が進むにつれてデータ量が増大することも考慮し、またより快適なレスポンスを得るためには検索条件となる項目を常にインデックス化することを推奨します。
Triggerでは10万件以上のデータから検索する時はインデックス化された項目が検索条件に含まれていないとエラーになる場合があります。TriggerではDMLが発行されてからコミットされるまでの間の処理を行うため、高い応答性能が求められるためです。
削除済みデータの考慮
Force.comアプリケーションのデータは次の3種類の状態があります。
1. Activeなデータ。通常の操作で参照・更新可能な状態
2. 削除され、ごみ箱に入っているデータ。ごみ箱から復元可能な状態
3. ごみ箱から削除され、内部的に物理削除されるのを待っている状態のデータ。画面上からは確認不可
上記の1.の状態のみでなく、2.および3.の状態で存在するデータの件数も検索のパフォーマンスに影響します。3.の状態のデータは一定間隔でバックグラウンドで物理削除されますが、大量のデータを削除した直後はクエリオプティマイザによるクエリ実行計画の最適化に反映されるまで1~2日程度かかる場合があります。
ちなみに、2.および3.の状態のデータは、SOQLクエリに isDeleted=TRUE および ALL ROWS を付加することによって取得・参照することができます。
[Select Field1__c, Field2__c, Field3__c From CustomObject__c Where isDeleted=TRUE ALL ROWS]
その他のチューニングの手段
Force.comプラットフォームにはDivisionという、データベースパーティションのような概念を持った機能があります。Divisionの方がパフォーマンス改善に対する効果は高いのですが、いろいろな制約があります。Divisionについてはまた別の機会に述べたいと思います。
レポートおよびリストビュー
本稿ではSOQLクエリの実行にフォーカスして述べていますが、レポートやリストビューの実行にもまったく同様のチューニングが適用可能です。レポートやリストビューの抽出条件に利用する項目がインデックス化されるようにすることで、レスポンスの改善を期待できます。
日々成長しています
ここに述べたようなチューニングを適切に行えば、数千万件のデータに対するクエリも実用上問題なく利用できます。弊社内で行ったテストでは、1億件以上のデータに対するクエリも実用的な応答性能が得られたという実績もあります。
Salesforceのデータセンターでは、24時間体制で常にサーバ負荷や応答性能の監視を行っています。インフラの増強も必要に応じて随時行っておりますので、ここで述べたようなパフォーマンスチューニングのノウハウも近い将来通用しなくなるかもしれません。サービスベンダーにより日々メンテナンスされ必要に応じた増強が行われるのもクラウドのメリットですね :-)
Cloudforce 2010 Japan 登録受付中です
by Mitsuhiro Okamoto on 9月 13, 2010 at 04:33 午後
セールスフォース・ドットコムの年間最大イベント「Cloudforce」が開催されます。
今年は10月5,6日と2日間をかけて、より多くの情報をお伝えする予定です。
開発者向けのDeveloper Sessionは2トラック6セッションありますので、皆様ご興味のあるセッションがありましたら奮ってご参加下さい!!
- D-3 「Force.comを使って開発をはじめてみよう 」
- H-4 「Force.comとChatterで簡単に作るソーシャルアプリケーション」
- H-5 「Apex, Visualforceを利用したビジネスアプリケーション開発」
- G-6 「セールスフォース・ドットコムの「マルチテナントアーキテクチャ」とは?」
他プラットフォームの開発者向け - 新しく発表されたセールスフォース・ドットコムのJavaクラウド「VMForce」など、既存のテクノロジを上手く活用してForce.comアプリケーションを構築のに役立つ方法をご紹介します。
- G-4 「SOAPとRESTを用いたWebサービスAPI接続手法」
- G-5 「Flash Builder for Force.comで作成するオフライン & モバイルアプリケーション」
- H-6 「セールスフォース・ドットコムのJavaクラウド「VMforce」概要」
Force.com Developer Lab
※ Labはご登録なしでご参加頂けます。
Force.com WorkbookやChatter Workbookを使って、実際にアプリケーション開発を体験できます。セールスフォース・ドットコムのエンジニアも会場に常駐していますので、技術的なご質問等がある場合にもご活用頂けます。
Winter '11の新機能情報
by Kaz Kawamura on 9月 8, 2010 at 02:28 午後
Salesforce.comの次期リリース、Winter '11の新機能に関して、こちらのページで公開されています。
ChatterのコンポーネントがVisualforceページに追加されたり、いろいろな機能が追加されていますが、開発者にとって注目の新機能は「System Log Console」。
こちらの機能を利用すると、従来のフラットなログからより詳しいApexの動作状況を参照できるようになります。たとえば、呼び出し階層を見てみたり、どのメソッドに多くの実行時間がかかっているか参照できたりします。
Apexコードを書かれる方以外はあまり関係ないかもしれませんが、開発者にとってはとてもうれしい機能だと思います!
Force.comプラットフォームのトランザクション制御
by Tetsuo Ajima on 9月 2, 2010 at 02:45 午後
開発の現場から良く出る質問にトランザクション制御関連が多いのでまとめてみました。
トランザクションスコープ
基本的に、Apexコードの呼び出しから終了までのすべての処理は1つのトランザクションにつながって実行されます。処理開始とともにトランザクションが開始され、処理終了時にコミットされます。コード中での明示的なBegin/Commitはありません。実行時例外が投げられるとトランザクションはロールバックされます。これはJavaEEの宣言的トランザクション仕様のRequired属性に似た動作と言えます。
Visualforce Controllerの場合は、Webクライアントからのリクエストを受けてからレスポンスを返すまでが1トランザクションとなります。Apexトリガの場合はトリガの起動から終了までが1トランザクションです。トリガ内で発行されたDMLによって起動したトリガもすべて同一トランザクションに組み込まれます。
SavepointとRollback
コード中で明示的に、ある時点までのロールバック処理を実行できます。 Database.setSavepoint()メソッドを使ってSavepointを設定し、Database.rollback(Savepoint sp)メソッドを呼ぶと指定したSavepointまでロールバックされます。ガバナ制限により、Savepointは1トランザクションにつき5つまで設定でき、ロールバック処理は1トランザクションにつき20回まで行えます。
// Savepointの作成
Savepoint sp = Database.setSavepoint();
・・・Database更新処理等・・・
// Savepoint設定時の状態までロールバック
Database.rollback(sp);
SELECT FOR UPDATE
Apexコード中で実行するSOQLクエリは、"for update"キーワードを付けて行ロックを取得することができます。行ロックはトランザクションがコミットまたはロールバックされるまで持続されます。
[Select Id From Account for update]
非同期処理
@futureアノテーションを付与したメソッドは別トランザクションとして実行されます。ガバナ制限も別計算になります。同一トランザクションではガバナ制限に抵触するような処理も、このアノテーションで処理を非同期化・別トランザクション化することにより実現できる場合があります。このメソッドの呼び出し時に行われるのはキューイングのみで、実際の実行タイミングは保証されないことに注意してください。また、呼び出し元のトランザクションが失敗すると呼び出し先の処理もコミットされません。
@futureアノテーションについての詳細は下記を参照してください。
http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_classes_annotation.htm
スレッドのWait/Notify/Sleep
@futureアノテーション等で処理を別スレッド化することはできますが、スレッドを停止したり処理を待ったり等のスレッド制御はできません。
また、Apexにはsynchronizedキーワードがありません。原則的に、永続化されたデータ以外にスレッド間でデータを共有するという仕組みが無いため、synchronizedキーワードも不要となっています。
トランザクションの分離レベル(Isolation level)
更新したがまだコミットされていないデータは、他のトランザクションからは読み取られません。JavaEE仕様の"Read Committed"に似た動作です。あるトランザクションが更新中のレコードを他のトランザクションが読み取ろうとしたときは、更新中トランザクションが終了するまで一定時間待ちます。一定時間を過ぎた場合は待っている方のトランザクションが失敗します。
Force.comプラットフォームでは、トランザクション分離レベルを変更することはできません。
ロングトランザクションの排他制御
Webアプリケーションにおける「ロングトランザクション」とは、複数回のリクエストにわたってレコードの一貫性の保証や排他制御を行う概念です。
一般的な設計方針では、データ取得時からレコードの更新時までレコードのロックを取得する「悲観的(Pesimistic )ロック」と、レコードの更新時のみにレコードのロックを取得する「楽観的(Optimistic)ロック」があります。
Webアプリケーションでよく用いられるのは、楽観的ロックです。悲観的ロックは、ロックステータスの管理を自前で実装したりロックのタイムアウトを実装したりが必要で、実装が複雑化してしまうという技術的な問題があります。(業務要件としても楽観的ロックの方がマッチする場合も多くみられます。)
楽観的ロックの実装では「バージョンカラム」がよく使われます。バージョンカラムとは、例えばInteger型の項目を作成しておき、レコードの取得時とコミット直前でこの値が変わっていなければ、バージョンカラム項目の値をインクリメントしてレコードをコミットするというものです。こうしておけば、他のトランザクションによりレコードが更新されているかどうかをバージョンカラムの値が変わっているかどうかをチェックすることにより検出できます。
Force.comでは、わざわざバージョンカラムを実装せずに、SystemModstamp項目を利用できます。SystemModstamp項目は、標準オブジェクト/カスタムオブジェクトのすべてにデフォルトで作成されている日付時間型の項目です。この項目はレコードに対して何らかの更新操作が行われるとシステムにより値が更新されるので、データ取得時とコミット直前でこの値が変わっていなければ他のトランザクションによる更新が行われていないという判断の根拠となります。
VMforceのWebinar
by Kaz Kawamura on 9月 2, 2010 at 11:03 午前
来週の木曜日 9/9に「Cloud Computing for Java Developers」というタイトルで、Java Developer向けのVMforceのWebinarが開催されます。こちらは、日本時間の夜10時からなので、日本からも参加しやすい時間です。Java Developerの皆さんにもぜひVMforceを知っていただきたいと思いますので、積極的なご参加、お待ちしています!
申込は、こちらのページからお願いします。
このWebinarは2回シリーズなのですが、第一回は先週の木曜ににすでに開催されています。こちらは、「Spring for force.com Developers」というタイトルです。内容は、Springに関してforce.com Developer向けにご紹介するもの。Java Developerに方ですでにSpringを利用して開発をしている方には少々入門的な内容です。こちらを聞き逃してしまった方、こちらのページでリプレイできますので、ぜひ見てみてください!


