はじめに
アプリケーションの速度が低下した場合、その問題は(少なくとも部分的に)データベースに関連している可能性が非常に高いです。
アプリケーションのパフォーマンス問題がデータベースに関係している可能性があると知ることは、遅延を減らすための良い第一歩です。難しいのは、これらのボトルネックがどこに、そしてなぜ存在するのかを見つけることです。
この記事では、データベースのパフォーマンスボトルネックを引き起こす最も一般的な問題と、それらを解決するために講じることができるいくつかの手順について説明します。
データベースのログとメトリクス
ログを見ずにデータベースのボトルネックを診断することはできません。ほとんどのクラウドプロバイダーは、クエリで何が起こっているかを評価するための豊富な情報を提供しますが、その情報が何を意味しているのかを理解するのは難しい場合があります。
ログ、メトリクス、およびクエリ統計を調べる
DigitalOcean、AWS、Google Cloud Platform、MongoDB Atlasなど、ほとんどのクラウドデータベースプロバイダーは、ログを表示できる場所を提供しています。後で問題をより簡単に見つけられるように、このログ情報のレイアウトと構造に慣れておくことが重要です。
例えばDigitalOceanでは、デプロイ管理メニューから直接アクセスできる「ログとクエリ」というタブが提供されています。
このセクションには、「最近のログ」というサブセクションがあり、リアルタイムでログ情報が表示されます。
これらのログに含まれる情報は、トラブルシューティングしようとしている特定のボトルネック問題に役立つ場合もあれば、そうでない場合もあります。ただし、セッション期間などの一部の情報は、データベースに長時間接続しているセッションの兆候を示す可能性があります。
メトリクスダッシュボードを調べる
クラウドデータベースプロバイダーのメトリクスダッシュボードは、発生している可能性のあるボトルネックについて最も深い洞察を与えてくれます。ほとんどのクラウドプロバイダーは、以下のようなパフォーマンス関連の情報を表示します。
- システムおよびプロセスのCPU使用率
- キャッシュ使用率
- メモリ
- 接続数
システムCPU使用率などの項目に関するメトリクスを表示すると、リソース制約に関連する問題が明らかになる場合があります。バックアップの取得などの管理タスクに関連する使用量の急増が見られることがあります。継続的な高い使用量は、データベースサーバーがプロビジョニング不足であることを示している可能性があります。
クエリ統計を調べる
クラウドデータベースプロバイダーからのクエリ統計レポートは、パフォーマンス低下の原因を特定するための最良の情報源となる可能性があります。多くの場合、パフォーマンス低下は実行に時間がかかるクエリに起因します。
クエリ統計はプロバイダーによってレポート方法が異なりますが、ほとんどの場合、プロバイダーは遅いと見なされるクエリを表示する方法を持っています。ほとんどのプロバイダーは、クエリステートメント、呼び出された回数、およびその特定のクエリのタイミングを表示します。
例えば、DigitalOceanのクエリ統計はこの情報を表形式で表示します。
インデックスが作成されていないテーブル
データベーステーブルのインデックスは、本の索引と概念的に似ています。本に索引がない場合、興味のあるトピックを見つけるためにすべてのページを調べなければなりません。代わりに、本に索引があれば、まず索引で特定のトピックを検索し、正しいページに案内されます。これにより、探している情報を見つけるのにかかる時間が大幅に短縮されます。
同じ概念がデータベースインデックスにも適用されます。データベーステーブルにインデックスを追加することで、高速なルックアップが可能になります。
テーブルに少量のデータから始めると、インデックスに関連する問題にすぐに気づかないことがよくあります。しかし、データが増加するにつれて、インデックスの欠如がより顕著になる可能性があります。
テーブルにインデックスを作成する
データベーステーブルのインデックスは、一般的なアクセスパターンに基づいて作成する必要があります。インデックスを作成する際には、インデックスを構築する列またはフィールドを指定します。
例えば、テーブルにemail
フィールドがあるusers
テーブルがある場合、アプリケーションにはメールアドレスに基づいてユーザーを検索するクエリがあるかもしれません。インデックスがない場合、クエリは正しいレコードを見つけるためにテーブル全体を検索します。代わりに、email
フィールドにインデックスを作成すると、クエリはまずインデックスを参照してメールアドレスの値を検索します。見つかると、そのユーザーの特定のデータベース行に案内されます。
インデックスを追加する機会を特定する最良の方法は、実行に時間がかかっているクエリを探すことです。この情報は、クラウドプロバイダーのデータベースダッシュボードの「クエリ統計」(または類似の)セクションで見つけることができます。
他の条件が同じであれば、使用されているアクセスパターンに対してインデックスを追加することにより、報告されているクエリの中で最も遅いものに最初に焦点を当てるのが最善です。その後、遅いクエリが解決されるまで、必要に応じてインデックスを追加していくことができます。
インデックスは生のSQLで作成できます。具体的なデータベースによって詳細は異なりますが、インデックスを作成するSQLコマンドは次のようになります。
CREATE INDEX email_index ON users (email);
インデックスが配置されたら、時間の経過とともにクエリ統計を調べて、パフォーマンスが向上したかどうかを確認してください。
遅いクエリの調査にEXPLAIN
を使用する
シナリオによっては、クラウドデータベースプロバイダーのクエリ統計ダッシュボードでは十分な情報が得られない場合があります。どのクエリが遅いかは示されても、どのインデックスを作成すべきか、あるいはクエリをどのように最適化すべきかは明確ではないかもしれません。
このような場合、EXPLAIN
ステートメントを使用してクエリを調査することを選択できます。このステートメントは通常のクエリと組み合わせて使用され、クエリ実行計画に関する詳細情報を取得するのに役立ちます。
例えば、PostgreSQLで通常のクエリの前に使用されるEXPLAIN
ステートメントは、以下のような情報を生成します。
- 推定起動コスト
- 推定合計コスト
- 推定出力行数
- 行の平均幅(バイト単位)
例えば、EXPLAIN
の以下の使用例では
EXPLAIN SELECT * FROM users;
このレポートを生成します
QUERY PLAN-------------------------------------------------------------Seq Scan on users (cost=0.00..458.00 rows=10000 width=244)
EXPLAIN
ステートメントは、特定のクエリを深く掘り下げ、そのコストを分析するための貴重なツールです。EXPLAIN
の使用から得られる情報は、クラウドプロバイダーがクエリ統計レポートで提供するものを超えており、クエリを最適化するために使用できます。
大量のデータ
最適化されていないクエリや範囲が広すぎるクエリは、データベースから過剰に大量のデータを返す可能性があります。これは、最小限のデータを持つ新しいデータベースで作業を開始する際には検出が難しいことが多いですが、データベースのサイズが大きくなるにつれて問題を引き起こす可能性があります。
クエリから大量のデータが返されると、データベースサーバーのメモリにスキャンされる必要があります。これによりCPUスパイクが発生し、バーストモードの使用が必要になる場合があります。これはデータベースサーバーのクラッシュにつながる可能性があります。もしデータがデータベースサーバーから返される場合、アプリサーバーがプロビジョニング不足であると、アプリサーバーが処理するには大きすぎる可能性もあります。
データの過剰取得に対処するには、関連するレコードに選択範囲を限定するようクエリを最適化する必要があります。解決策はしばしばWHERE
句を使用することですが、まず問題を引き起こしているクエリを見つける必要があります。
クラウドデータベースプロバイダーのログとメトリクスは、データベースから大量のデータが返されているという兆候を与える可能性があります。バーストクレジットの使用やCPUスパイクが見られるかもしれません。しかし、これらのメトリクスだけではどのクエリが原因であるかを判断するのは難しい場合があります。
アプリサーバーでの計測
大量のデータを返すクエリがどれであるかを完全に把握するには、アプリサーバーに計測機能を追加できます。New Relic、Datadog、Dynatraceなどのツールは、アプリサーバーを監視し、データが通過する際のサイズをレポートできます。アプリサーバーのどのエンドポイントや領域が大量のデータを処理しているかを調べることで、どのデータベースクエリが原因であるかを絞り込むのに役立ちます。
クエリの最適化
クエリの最適化は、画一的なものではなく、ケースに大きく依存します。ただし、考慮すべき一般的な最適化の種類がいくつかあります。
- 過剰取得を防ぐためにクエリの範囲を限定する - 適用可能な場合は必ず
WHERE
句を使用し、返されるデータの総量を減らしてください。 - 必要なフィールドのみを選択する - 多くの場合、テーブルのすべてのフィールドがアプリケーションに提供するために必要ではありません。過剰取得を防ぐために、アプリが必要とする特定のフィールドのみを選択してください。
- スキーマを監査する - データベースのスキーマを検査し、複雑さを軽減する機会を探します。多数の結合に依存するクエリは多くの場合実行が遅く、関係性を減らすようにスキーマを調整することで改善できます。
- データベースビューを使用する - ビューはテーブルに似ていますが、クエリを実行して事前に値を計算することで生成されます。これにより、その場で派生する可能性のある値を事前に計算できます。ビューには独自の注意点があり、すべてのアプリケーションやユースケースに適しているわけではありません。
結論
アプリケーションのパフォーマンス低下は、多くの場合データベースの問題に起因します。非常に頻繁に、これらの問題は最適ではないクエリに関連しています。
クエリの最適化に特効薬はありません。しかし、特定のクエリのパフォーマンスが低下している場所と理由を分析し、調査する努力は、調整すべき特定のクエリを絞り込むのに役立ちます。特定されたら、インデックスの追加、WHERE
句による範囲指定、必要なフィールドの選択といったクエリの調整を行うことで、はるかに優れたパフォーマンスが得られます。
Prismaを使用している場合、パフォーマンスと最適化のドキュメントで、クエリの測定と最適化について学ぶことができます。