拡張性パターン
パターン
| 参照すべき場所 | 外観 |
|---|---|
| SOQL クエリ効率 | 関連オブジェクトごとに個別のクエリを使用するのではなく、リレーションクエリ (Contacts、Cases__r) を使用してクエリを統合します。トランザクションごとに必要なすべてのデータを 1 回照会します。同期トランザクションでは 50 クエリ未満、非同期では 100 クエリ未満を目標とします (制限: 100 同期、200 非同期)。制限未満で 30 ~ 50% のバッファを維持する。 |
| DML 操作の一括処理 | レコードをリストに収集し、トランザクションごとにオブジェクト種別ごとに 1 つの DML ステートメントを実行します。部分的な成功動作を制御する allOrNone パラメーターで Database.insert/update/delete を使用します。トランザクションあたりの目標 <75 DML ステートメント (制限: 150)。バッチにより、DML の消費量が N ステートメントから 1 ステートメントに削減されます。 |
| ヒープサイズ管理 | 必須項目のみを照会します (SELECT * パターンは避けてください)。大きな結果セットをチャンクで処理します。処理後にコレクションをクリアしてメモリを解放します。同期コンテキストで 4 MB 未満のヒープ (制限: 6 MB)、非同期で 8 MB 未満のヒープ (制限: 12 MB) を対象とする。ヒープ超過エラーは、チャンクまたはストリーミングパターンが必要であることを示します。 |
| CPU 時間の最適化 | ループの計算量を最小限に抑えます。ネストされたリストの反復 (O(n²)) ではなく、Maps を使用してルックアップ (O(1)) を行います。重い計算を非同期コンテキストにオフロードします。同期トランザクションでは CPU が 7,000 ミリ秒未満 (制限: 10,000 ミリ秒)、非同期では 40,000 ミリ秒未満 (制限: 60,000 ミリ秒) を目標とします。 |
| SOQL クエリ行 | 合理的な結果セットサイズを返すクエリを設計する。LIMIT 句を使用して結果の上限を設定します。同期コンテキストでは、1 クエリあたり 25,000 行未満を目標とします (制限: 50,000)。制限に近づいているクエリでは、ページネーションを使用するか、バッチ Apex またはキュー可能を使用した非同期処理に移行する必要があります。 |
| API コールの割り当て | [システムの概要] で 24 時間の API 制限消費量を監視します。レコード単位のコールではなく、API 一括処理。プラットフォームキャッシュを使用して、頻繁にアクセスされる参照データをキャッシュします。急増に対応するため、1 日あたりの API 制限の 70% 未満を目標とします。API 制限は、エディションとライセンス数によって異なります。 |
| コールアウト制限 | 外部コールアウトの統合: 外部システムでサポートされる場合、複数のレコードを 1 つの API 要求に一括処理します。コールアウトを逐次化する要求キューを実装します。トランザクションあたりの合計コールアウト時間は 120 秒です。制限: トランザクションあたり 100 コールアウト。コールアウトの多いインテグレーションの非同期処理を設計します。 |
| コード (Apex、Aura、LWC) | 一括処理パターンを実装する: 個々のレコードではなくコレクションを処理し、Maps で 1 回照会してキャッシュし、オブジェクト種別ごとに 1 つの DML を実行します。SOQL の消費を最小限に抑えるには、リレーションクエリを使用します。大規模なデータセットでネストされたループを回避して効率的なアルゴリズムを適用します。 |
アンチパターン
| 参照すべき場所 | どんな悪い感じか |
|---|---|
| ループ内の SOQL | 問題: レコードコレクションを処理するループで内部で SOQL クエリを実行しています。影響: 100 件を超えるレコードでクエリ制限を超えました (制限: トランザクションあたり 100 件のクエリ)。解決策: クエリを 1 回実行してからループし、リレーション フィールドをキーとするマップに結果を保存します。Map inside ループからのルックアップ (一括処理パターン)。 |
| ループ内の DML | 問題: ループの内部で insert/update/delete ステートメントを実行しています。影響: 150 件以上のレコードで DML 制限を超えました (制限: トランザクションあたり 150 件の DML ステートメント)。解決策: レコードを収集してループ内のリストに含め、ループの完了後に 1 つの DML ステートメントを実行します。 |
| ガバナ制限バッファなし | 問題: 通常の状態でガバナ制限の 95% 以上を消費するトランザクションの設計。影響:負荷が若干増加したときに本番で障害が発生し、エッジ ケースの容量がありません。解決策: 制限の 70% を運用の上限として設定します。スパイクとエッジケース用に 30% のバッファを確保します。 |
| ネストされたループデカルト積 | 問題: ネストされたループが 2 つの大きなコレクションを繰り返し、O(n²) 操作を作成している。影響: CPU 制限超過エラー、一時的なオブジェクトからのヒープ制限の超過。解決策: O(n²) を O(n) に変換する地図ベースのルックアップを使用します。外側のループキーを収集し、関連レコードを 1 回照会し、内側のループで参照します。 |
| ヒープ蓄積 | 問題: 大きなクエリ結果をチャンクで処理せずにメモリに読み込む。影響: ヒープ制限を超えました。エラー (6 MB 同期、12 MB 非同期)。解決策: 必要な項目のみを照会。各バッチの後にコレクションをクリアするバッチで処理します。QueryLocator と一括処理 Apex を使用して、数百万件のレコードを処理します。 |
| 項目レベルの絞り込みなし | 問題: サブセットのみが必要な場合にすべてのフィールド (明示的または暗黙的) が選択される。影響: ヒープの過剰な消費、クエリ実行の遅さ、SOQL 行の制限が必要以上に近づいています。解決策: 処理に必要な項目のみを選択してください。リレーション表記を使用して、個別のクエリではなく 1 つのクエリで関連データを取得します。 |
| 同期処理の過剰使用 | 問題: 大量のデータをユーザートランザクション内で同期的に処理する。影響: ユーザーがマルチ秒操作を待機しています。CPU またはヒープの制限がユーザーをブロックしています。解決策: 重い処理を非同期コンテキスト(バッチ、キュー可能、プラットフォームイベント)に移行します。状況のポーリングでユーザーにすぐに応答します。 |
パターン
| 参照すべき場所 | 外観 |
|---|---|
| 非同期処理 | Batch Apexは、大量のレコード(数百万件)を処理する場合に使用します。Queueable Apex は、チェーンを使用した複雑な複数ステップのオーケストレーションに使用します。イベント駆動型の分離にはプラットフォームイベントを使用します。定期的なメンテナンスにはスケジュール済み Apex を使用します。非同期パターンを使用事例に一致させます: 量を表すバッチ、複雑さを表すキュー可能、分離を表すイベント。 |
| Apex 一括実装 | 処理されるレコードを最小限に抑えるために選択的な QueryLocator を返す start メソッドを設計します。レコードの複雑さ (実行あたり 200 ~ 2,000 レコード) に基づいてバッチサイズを設定します。ステートフル インターフェイスはスループットが低下するため、必要な場合にのみ実装してください。AsyncApexJob の成功/失敗を監視します。バッチでは、チャンクごとに専用のガバナ制限が提供されます。 |
| プラットフォームイベントアーキテクチャ | ダウンストリーム処理が必要な状態の変更に関するイベントを公開します。CometD を使用して、プラットフォーム イベント オブジェクトまたは外部登録者の Apex トリガーを使用して登録します。緊急登録者を設計します (リプレイで複数回イベントが配信される可能性があります)。一時的な登録者障害からの回復には 72 時間保持を使用します。 |
| 日付ベースのパーティショニング | 今月、前四半期、今年の期間でデータを処理します。履歴データを Big Object または外部ストレージにアーカイブします。時間ベースのパーティショニングにより、並列一括処理ジョブで異なる日付範囲を同時に処理できます。ほとんどのクエリは自然に日付で絞り込まれるため、効率的です。 |
| レコードタイプのパーティショニング | 異なるレコードタイプを個別に処理します。レコードタイプごとに個別の一括処理ジョブをスケジュールし、並列化を有効にします。多くの場合、レコードタイプは、独立した処理を正当化する個別のビジネスプロセスと相関します。組織ごとに最大 5 つの同時一括処理ジョブを実行するには、戦略的なパーティション分割が必要です。 |
| 地理ベースのパーティショニング | 配分を処理するために所有者、ディビジョン、またはテリトリー別にパーティション分割します。各地域、ビジネスユニット、または販売テリトリーを並列の一括処理ジョブで処理します。地理ベースのパーティション分割では、共有モデルが使用されます。各一括処理ジョブは、特定のユーザーグループのコンテキストで実行され、データが自然に絞り込まれます。 |
| キャッシュ戦略 | 頻繁にアクセスされる参照データには、プラットフォームキャッシュ (組織/セッションパーティション) を使用します。キャッシュにより、クエリと API の消費量が減少します。組織とセッションのパーティションを MB 単位で割り当てます。デフォルトの容量はエディションによって異なり、追加の容量はブロック単位で購入できます。キャッシュミスはクエリに適切にフォールバックする必要があります。キャッシュ TTL はデータ変更頻度と一致する必要があります (静的参照データの場合は時間、半動的の場合は分)。 |
| フローの一括処理 | ループ変数とコレクション変数を使用して、レコードコレクションを処理するフローを設計します。レコードコレクションの作成、1 つの [レコードを取得] の実行、1 つの [レコードを更新] 要素を使用したコレクションの更新。ループ内の個々のレコード操作は避けてください。フローの一括処理パターンは Apex のベストプラクティスを反映しています。 |
アンチパターン
| 参照すべき場所 | どんな悪い感じか |
|---|---|
| 順次処理のみ | 問題: 1 つの一括処理ジョブで 5,000 万件のすべてのレコードを 24 時間以上かけて順次処理します。影響: 他の処理、メンテナンス期間の枯渇、ユーザー対応の遅れをブロックします。解決策: 日付、レコードタイプ、または場所ごとにデータをパーティション分割します。独立したパーティションを同時に処理する並列一括処理ジョブを実行します。 |
| 同期インテグレーション連動関係 | 問題: 同期コールアウトを介して外部システム応答を待機中にブロックされたユーザートランザクション。影響: 外部システムのパフォーマンスに関連するユーザーエクスペリエンス、外部停止中のタイムアウトの失敗。解決策: プラットフォームイベントを使用して非同期インテグレーションを行います。ユーザートランザクションを外部システムの可用性から分離します。 |
| キャッシュレイヤーなし | 問題: トランザクション間で同じ参照データを繰り返し照会する。影響: SOQL の過剰な消費、API の制限の無駄、トランザクション実行の遅延。解決策: 頻繁にアクセスされる参照データにプラットフォームキャッシュを実装します。キャッシュにより、ガバナ制限の消費が減り、パフォーマンスが向上します。 |
| 一括処理ジョブスタッキング | 問題: 20以上の一括処理ジョブを同時に開始するようにスケジュールしている。影響: キューの深度の蓄積、同時ジョブの制限が 5 個で逐次化が発生し、完了時間が予測できません。解決策: 負荷を複数の時間に分散する時差スケジュール。動的派遣ロジックを使用して、類似するジョブを 1 つのバッチに統合します。 |
| ステートフルバッチの過剰使用 | 問題: Database を使用した一括 Apex の実装。必要のないときはステートフル。影響: execute() 呼び出し全体でインスタンスメンバー変数が不必要にシリアライズされ、保持状態からヒープが蓄積される可能性があります。解決策: ステートフルは、実行呼び出し全体でステートを維持する必要がある場合にのみ使用します。ステートレスバッチを優先し、ステートシリアライゼーションの不要なオーバーヘッドを回避します。 |
| シングルスレッドフロー設計 | 問題: 反復ごとに個々のレコード取得/更新要素を使用して、ループ内のレコードを 1 つずつ処理するフロー。影響:レコード件数に比例するガバナ制限の消費、大規模なトランザクションの失敗。解決策: コレクション変数にレコードを収集し、1 つの [レコードを取得] を実行し、ループ外の 1 つの [レコードを更新] 要素でコレクションを更新します。 |
| 非同期再試行戦略なし | 問題: 失敗した非同期ジョブは自動的に再試行されず、手動による介入が必要です。影響: データの不一致、手動による運用の負担、SLA の不履行。解決策: 指数バックオフを使用した自動再試行を実装します。プラットフォームイベントを使用して、耐久性のあるキューでリプレイを有効にします。AsyncApexJob を監視し、継続的な失敗についてアラートを表示します。 |
パターン
| 参照すべき場所 | 外観 |
|---|---|
| バッチとキューの選択 | Batch Apex は、数百万件のレコードのチャンク処理、スケジュールされた一括処理、データ移行に使用します。Queueable Apexを使用する用途:チェーンを使用した複数ステップのインテグレーション ワークフロー、複雑なオブジェクト パラメーターが必要な操作、@futureよりも優れた監視が必要なジョブ。非同期 Apex では、24 時間あたり 25 万件の実行の制限 (DailyAsyncApexExecutions) が、キュー可能固有の割り当てではなく、バッチ、キュー可能、将来、スケジュール済み Apex で共有されます。 |
| キュー可能チェーン | 現在のジョブの execute メソッドから次のジョブをキューに追加して、複数ステップのワークフローを実装します。チェーンを使用すると、コールアウト → 応答を解析 → フォローアップアクションをキューに追加という順序で処理できます。キュー可能な実行ごとに最大 1 つのエンキューでチェーンの暴走を回避します。完了検出を使用して無限ループを回避するチェーンを設計します。 |
| @future メソッドの使用 | @future は、複雑なパラメーター (プリミティブのみ) やチェーンを必要としない単純な非同期操作に使用します。制限: Apex トランザクションあたり 50 回の @future コール。@future は最も単純な非同期パターンを提供しますが、ジョブの監視、チェーン、複雑なパラメータがないため、可視性に欠けます。新規開発の場合は [キュー] を優先します。 |
| Apex 最適化のスケジュール | スケジュール済み業務を特定のハンドラーへの 1 つのスケジュール可能なクラス派遣に統合します。組織ごとに最大 100 件のスケジュール済みジョブを戦略的に統合する必要があります。業務時間外にスケジュールして、ユーザー操作との競合を減らします。オーケストレーションにスケジュール済みApexを使用し、重い処理をバッチApexに委任します。 |
| プラットフォームイベントのリプレイ | リプレイシナリオを処理する登録者を設計します (登録者が失敗した後の重複イベント、停止が長引いた後のギャップイベント)。登録者ごとに最終処理された ReplayId を維持する。EventBus.getReplayId() を使用して、リプレイイベントと新規イベントを検出します。即効性のある処理を実装する (同じイベントを 2 回処理すると同じ結果になる)。 |
| 継続パターン | 5秒を超える応答時間を必要とするLightningコンポーネントからの長時間のコールアウトには、[継続]を使用します。継続により、120 秒のコールアウトを複数同時に実行できるようになり、並列処理の知覚パフォーマンスが向上します。制限: 要求あたり 3 つの継続。タイムアウト処理とユーザーフィードバックを実装します。 |
インラインの例と詳細なガイダンスについては、信頼性の柱を参照するか、パターンとアンチパターンのエクスプローラーを参照してください。