Salesforce アーキテクトとして、エンタープライズレベルのソリューションを設計する際、最も重要な課題の一つは大規模データの管理です。ビジネスが成長し、顧客との接点が増えるにつれて、Salesforce 組織内に蓄積されるデータ量は指数関数的に増加します。このデータ爆発は、パフォーマンスの低下、ストレージコストの増大、ガバナ制限への抵触といった深刻な問題を引き起こす可能性があります。本稿では、これらの課題に対する Salesforce のネイティブな回答である Big Objects について、アーキテクトの視点からその背景、原理、設計上の考慮事項、そしてベストプラクティスを深く掘り下げて解説します。
背景と応用シナリオ
従来の Salesforce の標準オブジェクトやカスタムオブジェクトは、トランザクショナルなデータ処理(作成、読み取り、更新、削除)に最適化されており、リレーショナルデータベースの構造に基づいています。しかし、数億、数十億といったレコードを扱う場合、このモデルでは限界が生じます。クエリの実行時間が長くなり、レポートの生成が遅延し、最終的にはユーザーエクスペリエンス全体が悪化します。
ここで登場するのが Big Objects です。Big Objects は、Salesforce Platform 上で大量のデータを格納し、管理するために設計されたビッグデータベースのストレージシステムです。これらは、Apache HBase のような実績のあるビッグデータ技術を基盤としており、従来のオブジェクトとは根本的に異なる特性を持っています。アーキテクトとして Big Objects を検討すべき主な応用シナリオは以下の通りです。
顧客の360度ビューの実現
ウェブサイトのクリックストリーム、アプリケーションの利用ログ、購買履歴など、顧客に関する長期間にわたる詳細なインタラクションデータを保持するケースです。これらのデータを Big Objects にアーカイブすることで、主要な取引オブジェクト(取引先、商談など)のパフォーマンスを損なうことなく、顧客の全体像を把握するための分析やインサイト抽出に利用できます。
監査と追跡
金融サービスやヘルスケアなど、規制が厳しい業界では、長期間にわたる詳細な監査ログの保持が義務付けられています。フィールドの変更履歴、API コールのログ、ユーザーのアクセス記録などを Big Objects に格納することで、コンプライアンス要件を満たしつつ、主要な業務システムのパフォーマンスへの影響を最小限に抑えることができます。
IoT (Internet of Things) データの集約
多数のデバイスから送信されるセンサーデータやイベントデータをリアルタイムで収集・蓄積するシナリオです。Big Objects は、このような高頻度・大容量のデータストリームを効率的に処理し、将来の分析や機械学習モデルのトレーニングデータとして活用するための基盤となります。
データアーカイブ
最も一般的なユースケースです。完了した商談、クローズしたケース、過去のキャンペーン履歴など、頻繁にアクセスする必要はないが、記録として保持しておく必要があるデータを標準オブジェクトから Big Objects に移動させます。これにより、本番環境のデータ量を削減し、システム全体の応答性を維持することができます。
原理説明
Big Objects のアーキテクチャを理解する上で最も重要な概念は、そのインデックス(Index)とクエリの実行方法です。これらは標準オブジェクトとは大きく異なります。
カスタムインデックス:データアクセスの鍵
Big Objects のレコードは、定義時に指定された一連の項目から成るカスタムインデックス (Custom Index) に従ってソートされ、物理的に格納されます。このインデックスが、Big Objects の実質的な主キー(Primary Key)となります。
- 複合キー (Composite Key): インデックスは最大5つの項目で構成される複合キーです。
- 不変性 (Immutability): Big Object を一度作成すると、そのインデックスは変更できません。したがって、設計段階でどのようなクエリが実行されるかを正確に予測し、インデックスを慎重に設計することが極めて重要です。
- クエリの制約: 標準的な SOQL (Salesforce Object Query Language) を使用して Big Objects をクエリする場合、WHERE 句でインデックスを構成するすべての項目を完全に指定する必要があります。一部の項目だけを指定したり、範囲を指定したりすることはできません。この制約が、Big Objects の高速なデータ取得を可能にしています。
アーキテクトとして、どの項目をインデックスに含めるか、そしてその順序をどうするかは、ソリューション全体の成否を左右する最も重要な設計判断となります。
非同期 SOQL (Async SOQL)
インデックスに基づかない複雑な条件で Big Objects のデータをクエリしたい場合、非同期 SOQL (Async SOQL) を使用します。これは、大規模データセットに対してバックグラウンドで実行されるクエリです。
Async SOQL は、リクエストをキューに投入し、Salesforce がリソースの空き状況に応じて処理を実行します。結果は指定された Salesforce オブジェクト(通常はカスタムオブジェクト)に格納されるため、リアルタイムの応答は得られません。この非同期性という特性を理解し、バッチ処理やデータ分析基盤への連携といったシナリオで活用することが求められます。
API アクセス
データの挿入には、Apex の `Database.insertImmediate()` メソッドや Bulk API 2.0 が主に使用されます。特に数十万件以上のデータを一度にロードする場合は、Bulk API 2.0 の利用が推奨されます。
示例代码
ここでは、Big Objects の定義、データ挿入、そして非同期クエリの具体的なコード例を見ていきましょう。これらのコードは Salesforce の公式ドキュメントに基づいています。
1. Big Object のメタデータ定義
Big Object は、UI からではなく、メタデータ API を通じて `objects` フォルダ内に `.object` ファイルを配置してデプロイします。以下は、顧客の操作履歴を記録する `Customer_Interaction__b` という Big Object の定義例です。
<?xml version="1.0" encoding="UTF-8"?>
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
<deploymentStatus>Deployed</deploymentStatus>
<fields>
<fullName>Account__c</fullName>
<label>Account</label>
<referenceTo>Account</referenceTo>
<relationshipName>Interactions</relationshipName>
<required>true</required>
<type>Lookup</type>
</fields>
<fields>
<fullName>Interaction_DateTime__c</fullName>
<label>Interaction DateTime</label>
<required>true</required>
<type>DateTime</type>
</fields>
<fields>
<fullName>Interaction_Type__c</fullName>
<label>Interaction Type</label>
<length>255</length>
<required>false</required>
<type>Text</type>
</fields>
<indexes>
<!-- このインデックスが Big Object の主キーとなる -->
<!-- クエリはこの2つの項目を完全に指定する必要がある -->
<fullName>CustomerInteractionIndex</fullName>
<label>Customer Interaction Index</label>
<fields>
<name>Account__c</name>
<sortDirection>ASC</sortDirection>
</fields>
<fields>
<name>Interaction_DateTime__c</name>
<sortDirection>DESC</sortDirection>
</fields>
</indexes>
<label>Customer Interaction</label>
<pluralLabel>Customer Interactions</pluralLabel>
</CustomObject>
この例では、`Account__c` (取引先への参照) と `Interaction_DateTime__c` (操作日時) をインデックスとして定義しています。これにより、「特定の取引先の、特定の時間における操作」を高速に取得できます。
2. Apex を使用したデータ挿入
Apex から Big Objects にレコードを挿入するには `Database.insertImmediate()` を使用します。`DML (Data Manipulation Language)` 操作は同期的ですが、トランザクションの対象外です。
// 挿入する Big Object レコードのリストを作成
List<Customer_Interaction__b> interactions = new List<Customer_Interaction__b>();
// 新しいレコードをインスタンス化
Customer_Interaction__b interaction1 = new Customer_Interaction__b();
interaction1.Account__c = '001xx000003DHPpAAO'; // 有効な取引先 ID を設定
interaction1.Interaction_DateTime__c = Datetime.now();
interaction1.Interaction_Type__c = 'PageView';
Customer_Interaction__b interaction2 = new Customer_Interaction__b();
interaction2.Account__c = '001xx000003DHPqAAO'; // 有効な取引先 ID を設定
interaction2.Interaction_DateTime__c = Datetime.now().addMinutes(-10);
interaction2.Interaction_Type__c = 'FormSubmit';
interactions.add(interaction1);
interactions.add(interaction2);
// Database.insertImmediate を使用してレコードを挿入
// この操作はガバナの DML 行数制限にはカウントされないが、独自の制限がある
Database.SaveResult[] results = Database.insertImmediate(interactions);
// 結果をチェック
for (Database.SaveResult res : results) {
if (res.isSuccess()) {
System.debug('Successfully inserted Big Object record. ID: ' + res.getId());
} else {
for (Database.Error err : res.getErrors()) {
System.debug('Error inserting record: ' + err.getStatusCode() + ': ' + err.getMessage());
}
}
}
3. 非同期 SOQL (Async SOQL) の実行
特定の期間内に「PageView」操作を行ったすべての取引先を抽出するなど、インデックス全体を使用しないクエリには Async SOQL を使用します。結果は `Target_Object__c` というカスタムオブジェクトに格納する例です。
// 結果を格納するためのターゲットオブジェクト
// Name (取引先ID)、Count__c (操作回数) の項目を持つカスタムオブジェクトを想定
AsyncSOQL_Result_Target__c targetObject = new AsyncSOQL_Result_Target__c();
insert targetObject;
// Async SOQL クエリを文字列として定義
// COUNT_DISTINCT を使用してユニークな取引先の数をカウント
String query = 'SELECT Account__c, COUNT(Id) ' +
'FROM Customer_Interaction__b ' +
'WHERE Interaction_Type__c = \'PageView\' ' +
'GROUP BY Account__c';
// Async SOQL ジョブの設定
AsyncSOQLOptions options = new AsyncSOQLOptions();
options.targetObject = 'AsyncSOQL_Result_Target__c';
options.targetField = 'Job_Result__c'; // 結果 (CSV) を格納する Long Text Area 項目
// ジョブを開始
String jobId = System.enqueueAsyncSOQL(query, options);
System.debug('Async SOQL Job ID: ' + jobId);
このジョブが完了すると、`AsyncSOQL_Result_Target__c` の `Job_Result__c` 項目にクエリ結果が CSV 形式で格納されます。アプリケーションはジョブのステータスを監視し、完了後に結果を処理する必要があります。
注意事項
アーキテクトとして Big Objects をソリューションに組み込む際には、以下の点に細心の注意を払う必要があります。
インデックス設計は後戻りできない
前述の通り、インデックスは一度作成すると変更できません。インデックス設計を誤ると、データが実質的に利用不可能になる可能性があります。データアクセスパターンを徹底的に分析し、最も頻繁に使用されるフィルタ条件をインデックスに設定してください。インデックス内の項目の順序もクエリパフォーマンスに影響するため、カーディナリティ(値のばらつき)が高い項目を先に配置することが一般的です。
機能的な制約の理解
Big Objects は、標準オブジェクトが持つ多くの機能をサポートしていません。
- UI 非対応: 標準のタブ、ページレイアウト、関連リストは存在しません。データ可視化には、LWC (Lightning Web Components) を用いたカスタムコンポーネント開発や、外部の BI ツール(Tableau など)との連携が必要です。
- 自動化ロジック非対応: トリガ、ワークフロールール、プロセスビルダー、フローは実行されません。
- 共有とセキュリティ: レコードレベルの共有ルールは適用されません。オブジェクト全体の権限(プロファイル/権限セット)のみでアクセスを制御します。
- 数式項目と積み上げ集計項目: サポートされていません。
API とガバナ制限
Big Objects にも独自の制限があります。例えば、1組織あたりに作成できる Big Objects の数(デフォルトで100)、Async SOQL の24時間あたりのジョブ実行数などです。設計段階でこれらの制限を考慮し、大規模なデータ処理が制限に抵触しないか評価することが重要です。
まとめとベストプラクティス
Salesforce Big Objects は、正しく理解し、適切なシナリオで活用すれば、大規模データ管理の課題を解決する強力なツールとなります。アーキテクトとしては、単なる技術的な選択肢としてではなく、システム全体のパフォーマンス、コスト、拡張性を見据えた戦略的な要素として捉えるべきです。
ベストプラクティス
- ユースケースの厳密な評価: Big Objects は万能ではありません。「データ量が多いから」という理由だけで採用するのではなく、データの性質(トランザクショナルか、アーカイブか)、アクセス頻度、クエリパターンを分析し、本当に Big Objects が最適かを見極めてください。場合によっては、外部のデータウェアハウスや、標準オブジェクトとスキニーテーブルの組み合わせの方が適していることもあります。
- インデックス第一の設計アプローチ: まず、どのようにデータを照会したいかを定義します。そのクエリパターンに基づいて、最適なインデックスを設計します。このプロセスをデータモデリングの中心に据えてください。
- 包括的なデータライフサイクル管理: データの投入(Ingestion)、活用(Utilization)、そして最終的な廃棄(Deletion)まで、ライフサイクル全体を考慮したアーキテクチャを設計します。データの投入には Bulk API 2.0、活用には Async SOQL と LWC、廃棄にはバッチ Apex を組み合わせるなど、各フェーズに最適なツールを選択します。
- ユーザーエクスペリエンスを忘れない: データが Big Objects に格納されていることをエンドユーザーに意識させてはいけません。カスタム LWC を通じて、あたかも標準オブジェクトのデータであるかのようにシームレスに表示・操作できるインターフェースを提供することが、ソリューションの成功には不可欠です。
結論として、Salesforce Big Objects は、プラットフォーム上でスケーラブルなデータソリューションを構築するための重要なコンポーネントです。その特性と制約を深く理解し、戦略的に設計に組み込むことで、Salesforce 組織の長期的な健全性とパフォーマンスを確保することができるでしょう。
コメント
コメントを投稿