データベースを変更する前に高コストのリクエストを見つける
カテゴリ表示、記事検索、カートへの追加、注文送信など、ユーザーの操作から始めます。その経路、クエリ数、データベース処理時間、返された行数、リクエスト時間を記録してください。ページの遅延はアプリケーションコードや他の依存先が原因の場合もあるため、ページ読み込み時間だけで診断してはいけません。
実行計画はテーブル、インデックス、結合、ソート、集計を通るデータベースの経路です。PostgreSQL では EXPLAIN がその経路を示します。EXPLAIN ANALYZE はステートメントを実行し、実際の行数とタイミングを報告するので、代表的で安全なクエリを使ってください。推定行数と実際の行数に大きな乖離がある場合は、統計や条件を調査する理由になりますが、自動的にインデックスを追加すべきという意味ではありません。
候補クエリを経路と結果に結び付け、ダッシュボードだけのレポートが遅いチェックアウトより優先されないようにします。
変更前の計測値と比較可能なトラフィックを記録します。顧客識別子、トークン、カード関連値は記録しないでください。
実際に使うアクセス経路に合わせてインデックスを設計する
インデックスは行の位置特定や順序で返すのを助ける維持構造であり、万能の高速化スイッチではありません。まず重要なクエリのフィルタ、結合キー、ソート順を確認し、提案するインデックスが実行計画で有効か確かめてください。PostgreSQL のドキュメントは、マッチする B-tree インデックスが、特に小さな LIMIT と組み合わせた場合に、別個のソートなしで ORDER BY を満たせることを示しています。
インデックスはストレージと書き込みコストを増やします。挿入・更新・削除でインデックスが維持されるからです。テーブルの大部分が必要なクエリでは、シーケンシャルスキャンと明示的なソートの方が速い場合があります。本番に近いデータでテストし、利益がコストに見合う場合にのみインデックスを維持してください。
クエリの実際のフィルタと ORDER BY を使い、インターフェイスが安定した順序を必要とする場合は決定論的なタイブレーカーを含めてください。
インデックスが使われているか、書き込み時に何をコストとしているかをレビューし、データやトラフィックが変わったら再確認してください。
ページネーションを安定かつ負担の少ないものにする
ページ番号方式のページネーションは通常 LIMIT と OFFSET を使います。必ず予測可能な順序を課してください。PostgreSQL は ORDER BY がないと LIMIT が予測不能なサブセットを返す可能性があると警告しており、異なる LIMIT や OFFSET 値で最適化器が別の計画を選ぶため、一貫しない結果になることがあります。
大きな OFFSET は注意が必要です。スキップされた行も計算されるためです。カタログの深い閲覧、注文履歴、アーカイブ閲覧には、カーソルやキーセット(keyset)ページネーションを検討してください:最後に見た安定したソート値と一意のタイブレーカーの後の行を要求します。インターフェイス変更前に、新規または削除されたレコードがどう現れるか定義してください。
無制限の結果ではなく、最小限で有用なページを返してください。
インターフェイスが本当に毎回正確な総件数を必要としているか決めてください。
誤った応答を返さないように読み取りをキャッシュする
キャッシュはデータベースから再構築する代わりに以前の結果を再利用します。公開され、繰り返し参照されるページやバージョン管理されたアセットではまず HTTP レイヤーから始めてください。キャッシュヒットはアプリケーションとデータベースの作業を回避できます。web.dev はバージョン付き URL に対する長寿命キャッシュを推奨しており、URL を変更することが実用的な無効化手段です。
キャッシュポリシーは正確性(correctness)の判断です。共有キャッシュは1つの応答を複数のユーザーで再利用するため、アカウント、カート、価格、認可固有の出力は、そのスコープで設計およびテストされていない限り共有しないでください。Cache-Control の private はブラウザキャッシュへの再利用に制限し、no-store はキャッシュに保持しないよう指示します。
公開カタログや記事の出力を、セッション固有、位置情報固有、権限感度の高い出力と分けてください。
誰がどの程度古い値を許容するか、期間、および無効化または再検証の経路を定義してください。
単に上限を上げる代わりに接続容量を保護する
接続はデータベースへのライブなクライアントセッションです。ワーカー、cron ジョブ、プレビュー、リトライがスロットを使い果たすことがあり、個々のクエリが許容範囲で見えても枯渇する場合があります。PostgreSQL の max_connections は同時接続数を制御し、サーバ起動時に設定され、値を大きくすると共有メモリを含むより多くのリソースが割り当てられます。ワークロードモデルなしで引き上げると失敗が別の形で移動する可能性があります。
Web ワーカー、バックグラウンドジョブ、管理操作、レプリカをまたいで1つの予算を設定してください。適切な箇所でバウンデッドプーリングを使い、復旧のための余裕を残し、放置された作業が無期限に待たないようタイムアウトを適用します。安全な数値はエンジン、メモリ、クエリの混在、プロバイダ制限によって異なるため、運用担当者と確認してください。
Web プロセス、キュー、定期タスク、マイグレーション、レポーティングツール、デプロイジョブを含めてください。
同時実行数を上限し、フォールトが接続需要を増幅しないようバックオフを使ってください。
文脈とプライバシー制御でクエリコストを観測する
データベースの作業は単一の遅いサンプルではなく、総合的な影響で順位付けしてください。数千回呼ばれる中程度に遅いクエリの方がまれなレポートより重要なことがあります。PostgreSQL の pg_stat_statements は呼び出し数、合計・平均実行時間、行数、バッファ活動などを集約します。これを追加・削除するにはサーバ設定と再起動が必要で、プランニングの追跡はオーバーヘッドを伴います。
クエリグループを経路、リリースバージョン、時間窓に結び付けてください。OpenTelemetry はリテラルを置換してサニタイズした後にクエリテキストを収集すること、グルーピングには低カードinality のクエリサマリを使うことを推奨しています。これによりオーナーは顧客データをエクスポートしたり、あらゆる値のためのラベルを作成することなく傾向を把握できます。
期間、合計時間、呼び出し回数、エラー、接続、行数を確認してください。それぞれが異なる失敗モードを露呈します。
パラメタライズドクエリを使い、トレースやログがアプリケーション外に出る前にリテラルが除去されていることを検証してください。
信頼性を損なわない形でデータベース変更を出荷する
インデックス、リライト、キャッシュポリシー、プール設定、スキーマ変更は、オーナー、成功計測、ロールバック判断を持つ本番変更として扱ってください。代表的な環境で検証し、限定的なスライスへリリースして影響を受ける経路を監視します。速くなっただけでは、変更が誤った、欠落した、重複した、または古いデータを返すなら成功ではありません。
スキーマ変更は特に注意が必要です。アプリケーションのバージョンが重複する可能性があるためです。Google Cloud のガイダンスは互換性の順序を説明しています:古いスキーマと新しいスキーマの両方を扱えるアプリケーションをまずリリースし、次にスキーマを変更し、最後にそれを使う機能をリリースする、という流れです。これによりアプリケーションのロールバック経路が保存されます。ロックやオンライン変更の挙動はエンジンやマネージドサービスで異なるため、高負荷や支払い関連システムでは適格なレビューを受けてください。
経路、性能と正確性のシグナル、ロールアウトを停止する閾値を明示してください。
統制されたスライスで性能と正確性を検証してから拡大し、インシデント時以外で戻る手順を練習してください。
