執筆者:Salesforce アーキテクト
背景と応用シナリオ
Salesforceは世界をリードするCRMプラットフォームとして、日々膨大な量のデータを処理しています。特に、数百万、数千万レコードを扱うLarge Data Volume (LDV, 大量データ) 環境では、パフォーマンスの維持が極めて重要な課題となります。このLDV環境において、パフォーマンス低下の主要な原因の一つが Data Skew (データスキュー)、日本語では「データの偏り」と呼ばれる現象です。
データスキューとは、特定の親レコードに極端に多数の子レコードが関連付けられたり、特定のユーザーが極端に多数のレコードを所有したりすることで、データ分布が不均衡になる状態を指します。Salesforceアーキテクトとして、我々はこのデータスキューをシステムの設計段階から考慮し、スケーラブルで高性能なソリューションを構築する責任があります。データスキューを放置すると、以下のような深刻な問題を引き起こす可能性があります。
- パフォーマンスの低下:レポートやリストビューの読み込みが遅延する、SOQLクエリがタイムアウトする。
- レコードロックの競合:多数の子レコードを更新する際に親レコードがロックされ、トランザクションが失敗する(`UNABLE_TO_LOCK_ROW` エラー)。
- 共有計算の遅延:ロール階層や共有ルールの変更時に、共有テーブルの再計算に非常に長い時間がかかり、システムの可用性に影響を与える。
- DML操作の失敗:一括処理やインテグレーションにおいて、ガバナ制限に抵触しやすくなる。
具体的なシナリオとしては、「すべての子会社や部門の取引先責任者を、単一の親『本社』取引先に紐付ける」「システム連携用の単一ユーザーに、何百万ものケースレコードを所有させる」といったケースが挙げられます。これらの設計は一見シンプルですが、組織の成長とともにデータスキューを引き起こし、やがてはシステム全体のボトルネックとなります。本記事では、Salesforceアーキテクトの視点からデータスキューの原理を解説し、その特定方法とベストプラクティスについて詳述します。
原理説明
データスキューは主に3つのタイプに分類されます。それぞれのメカニズムを理解することが、効果的な対策を講じるための第一歩です。
1. Account Skew (アカウントスキュー)
Account Skew (アカウントスキュー)は、単一の取引先 (Account) レコードに、10,000件を超える子レコード(取引先責任者、商談、ケースなど)が関連付けられている状態を指します。Salesforceの内部では、子レコードが更新される際、関連する親レコードにロックがかけられることがあります。これはデータの整合性を保つための重要な仕組みですが、アカウントスキューが発生している場合、多数のトランザクションが同時に単一の親取引先をロックしようと試みるため、Record Locking (レコードロック) の競合が頻発します。
例えば、多数のユーザーが同じ親取引先に紐づく異なる取引先責任者を同時に編集しようとすると、最初のユーザーのトランザクションが完了するまで、他のユーザーは待機させられるか、エラーを受け取ることになります。これにより、ユーザーエクスペリエンスが著しく低下し、特にAPI連携などの自動処理では大量のエラーが発生する原因となります。
2. Ownership Skew (所有権スキュー)
Ownership Skew (所有権スキュー)は、単一のユーザーまたはキューが、あるオブジェクトのレコードを極端に多く(通常は10,000件以上)所有している状態を指します。この問題の核心は、Salesforceの共有モデル、特にロール階層に基づいた共有の仕組みにあります。
ユーザーが新しいレコードを作成したり、所有権が変更されたりすると、Salesforceはそのレコードへのアクセス権を決定するために共有計算を実行します。所有者がロール階層に属している場合、その所有者の上司、さらにその上司…と階層を遡ってアクセス権が付与されます。所有権スキューが発生しているユーザーがロール階層の変更、公開グループへの追加・削除の対象となると、そのユーザーが所有する膨大な数のレコードすべてに対して共有再計算がトリガーされます。この処理は非常に負荷が高く、完了までに数時間、場合によっては数日を要することもあり、その間、組織全体の共有設定に関連する操作が不安定になる可能性があります。
3. Lookup Skew (ルックアップスキュー)
Lookup Skew (ルックアップスキュー)はアカウントスキューの概念を一般化したもので、あるオブジェクトの大量のレコードが、別のオブジェクトの単一レコードに参照関係(Lookup)で紐付いている状態を指します。例えば、すべてのカスタムオブジェクトレコードが、単一の「設定」レコードを参照しているようなケースです。
アカウントスキューと同様に、多数の子レコードから単一の親レコードへの参照が集中することで、レコードロックの競合が発生しやすくなります。特に、子レコードの更新がトリガーや入力規則などで親レコードの情報を参照・更新する場合に、パフォーマンスへの影響が顕著になります。
示例代码
データスキューは問題が発生する前に特定し、対処することが重要です。以下に、SOQLクエリを使用してデータスキューの兆候を検出するためのサンプルコードを示します。これらのクエリは、開発者コンソールや任意のAPIツールで実行できます。
アカウントスキューの特定
このクエリは、最も多くの取引先責任者を持つ取引先の上位10件を特定します。カウントが10,000を超えている場合、アカウントスキューのリスクが高いと判断できます。
/* * AccountId ごとに Contact レコードの数を集計します。 * COUNT(Id) で各AccountIdに紐づく子レコードの数を数えます。 * GROUP BY AccountId で取引先ごとにグループ化します。 * ORDER BY COUNT(Id) DESC で子レコード数の多い順に並べ替えます。 * LIMIT 10 で上位10件に結果を絞ります。 */ SELECT AccountId, COUNT(Id) FROM Contact GROUP BY AccountId ORDER BY COUNT(Id) DESC LIMIT 10
⚠️ このクエリは developer.salesforce.com のSOQLドキュメントに記載されている標準的な集計クエリの応用です。
所有権スキューの特定
このクエリは、最も多くのケースレコードを所有しているユーザーまたはキューの上位10件を特定します。大量のレコードを所有する単一の「連携用ユーザー」などがいないか確認するために使用します。
/* * OwnerId ごとに Case レコードの数を集計します。 * 所有者 (User または Queue) ごとにグループ化し、レコード数をカウントします。 * レコード数の多い順に上位10件の所有者を表示します。 * このクエリは Case オブジェクトを対象としていますが、 * 他のオブジェクト(Lead, Custom_Object__c など)にも応用可能です。 */ SELECT OwnerId, COUNT(Id) FROM Case GROUP BY OwnerId ORDER BY COUNT(Id) DESC LIMIT 10
⚠️ このクエリも同様に、Salesforceの標準的なSOQL集計機能に基づいています。
注意事項
データスキューへの対応を計画・実行する際には、以下の点に注意する必要があります。
- 権限 (Permissions): 上記のクエリを実行するには、対象オブジェクトに対する「参照」権限が必要です。また、組織全体のデータを分析するには「すべてのデータの参照」権限が必要になる場合があります。
- API 制限 (API Limits): 対象オブジェクトのレコード数が非常に多い場合、集計クエリであってもガバナ制限(CPUタイムアウトなど)に達する可能性があります。その場合は、Batch ApexやBulk API 2.0 Queryを使用して、非同期で大規模なデータセットを分析することを検討してください。
- エラー処理 (Error Handling): データスキューが存在する環境でデータを操作するApexコードやインテグレーションを開発する際は、`UNABLE_TO_LOCK_ROW` のようなロック競合エラーを想定したエラーハンドリングとリトライロジックを実装することが不可欠です。
- データ移行のインパクト: スキューを解消するためにデータの再分配(例えば、親取引先の分割や所有者の変更)を行う場合、大規模なデータ移行が必要となります。移行計画は慎重に立て、関連するトリガー、自動化プロセス、共有ルールへの影響を十分にテストする必要があります。ダウンタイムを最小限に抑えるための戦略も重要です。
まとめとベストプラクティス
Salesforceアーキテクトとして、データスキューは単なる技術的な問題ではなく、ビジネスの成長を支えるための重要な設計上の考慮事項です。スケーラブルなシステムを構築するためには、以下のベストプラクティスを設計の初期段階から取り入れることが推奨されます。
1. データ分布の均等化
単一のレコードにデータが集中しないように設計します。例えば、未割り当ての取引先責任者を格納するための「ダミー取引先」を一つだけ作成するのではなく、アルファベットや地域ごとなど、複数の「バケット取引先」を作成して負荷を分散させます。
2. 所有権戦略の見直し
データ連携や一括処理で使用するユーザー(Integration User)は、ロール階層の最上位や多くの部下を持つマネージャーのロールに配置しないでください。可能であれば、ロールを持たない専用のプロファイルを作成し、そのユーザーをロール階層の外に置くことで、共有再計算の連鎖を防ぎます。また、レコード所有も単一の連携ユーザーに集中させるのではなく、複数の連携ユーザーに分散させることを検討します。
3. 共有モデルの最適化
ロール階層に依存した共有がパフォーマンスのボトルネックになる場合は、Criteria-Based Sharing Rules (条件に基づく共有ルール) や、Apex Managed Sharingといったプログラムによる共有を積極的に活用します。これらはロール階層の変更に影響されにくく、より予測可能でスケーラブルな共有モデルを構築できます。
4. 定期的なモニタリング
データスキューは、ビジネスの成長とともに徐々に進行します。先に紹介したSOQLクエリを定期的に実行し、レポートやダッシュボードでデータの偏りを可視化する仕組みを構築してください。これにより、問題が深刻化する前に兆候を捉え、プロアクティブに対策を講じることが可能になります。
5. データアーカイブ戦略
アクティブでなくなった古いレコード(例えば、完了してから数年経過したケース)は、Salesforceのパフォーマンスに影響を与えます。定期的に外部ストレージ(Big Objectsや外部データベースなど)にアーカイブする戦略を立て、本番環境のデータ量を最適に保つことで、スキューの影響を軽減します。
結論として、データスキューは避けるべき課題であると同時に、Salesforceプラットフォームの能力を最大限に引き出すための設計力が試される領域でもあります。アーキテクトは、常にデータの成長と分布を念頭に置き、長期的な視点で堅牢なソリューションを設計することが求められます。
コメント
コメントを投稿