はじめに
アプリケーションの速度が低下した場合、問題はデータベースに(少なくとも部分的に)関連している可能性が非常に高いです。
アプリケーションのパフォーマンスの問題がデータベースに関連している可能性があることを知ることは、遅延を減らすための良い第一歩です。難しいのは、これらのボトルネックが*どこ*に、そして*なぜ*存在するのかを突き止めることです。
この記事では、データベースでパフォーマンスのボトルネックを引き起こす最も一般的な問題と、それらを改善するために講じることができるいくつかの手順について説明します。
データベースログとメトリクス
ログを見ずにデータベースのボトルネックを診断することはできません。ほとんどのクラウドプロバイダーは、クエリで何が起こっているかを評価するための豊富な情報を提供していますが、その情報が何を言っているのかを理解するのは難しい場合があります。
ログ、メトリクス、クエリ統計を調べる
DigitalOcean、AWS、Google Cloud Platform、MongoDB Atlasなど、ほとんどのクラウドデータベースプロバイダーは、ログを表示する場所を提供しています。後で問題をより簡単に見つけられるように、このログ情報のレイアウトと構造に慣れておくことが重要です。
たとえば、DigitalOceanは、デプロイメント管理メニューから直接アクセスできる「ログとクエリ」というタブを提供しています。
このセクションには、「最近のログ」というサブセクションがあり、ログ情報がリアルタイムで表示されます。
これらのログに含まれる情報は、トラブルシューティングしようとしている特定のボトルネックの問題に役立つ場合もあれば、そうでない場合もあります。ただし、セッション期間などの一部の情報は、データベースへの接続に長時間費やしているセッションの兆候を示す可能性があります。
メトリクスのダッシュボードを調べる
クラウドデータベースプロバイダーのメトリクスダッシュボードは、発生している可能性のあるボトルネックに関する最も深い洞察を提供します。ほとんどのクラウドプロバイダーは、次のようなパフォーマンス関連の情報を示しています。
- システムおよびプロセスのCPU使用率
- キャッシュ使用率
- メモリ
- 接続数
システムCPU使用率などの項目のメトリクスを表示すると、リソース制約に関連する問題が明らかになる場合があります。バックアップの実行などの管理タスクに関連する使用率の急上昇が見られる場合があります。持続的な高使用率は、データベースサーバーのプロビジョニングが不足していることを示している可能性があります。
クエリ統計を調べる
クラウドデータベースプロバイダーからのクエリ統計レポートは、速度低下の原因を特定するための最良の情報源となる可能性があります。多くの場合、速度低下は、実行に時間がかかるクエリに起因する可能性があります。
クエリ統計はプロバイダーによって報告方法が異なりますが、ほとんどの場合、プロバイダーは遅いと見なされるクエリを表面化する方法を持っています。ほとんどのプロバイダーは、クエリステートメント、呼び出された回数、および特定のクエリのタイミングを表示します。
たとえば、DigitalOceanのクエリ統計は、この情報を表形式で表示します。
インデックスなしのテーブル
インデックスは、データベーステーブルにおいて、概念的には本の索引に似ています。本に索引がない場合、目的のトピックを見つけるためにすべてのページを調べる必要があります。代わりに、本に索引がある場合、最初に索引で特定のトピックを検索すると、正しいページまたはページが示されます。これにより、探している情報を見つけるのにかかる時間が大幅に短縮されます。
同じ概念がデータベースインデックスにも適用されます。データベーステーブルにインデックスを追加すると、高速な検索が可能になります。
テーブル内のデータ量が少ない状態で開始した場合、インデックス作成に関連する問題にすぐには気付かないのが一般的です。ただし、データが増加するにつれて、インデックス作成の欠如がより顕著になる可能性があります。
テーブルのインデックスを作成する
データベーステーブルのインデックスは、一般的なアクセスパターンに基づいて作成する必要があります。インデックスを作成するときは、インデックスを構築する列またはフィールドを指定します。
たとえば、テーブルに`users`テーブルのemail
フィールドがある場合、アプリケーションに電子メールに基づいてユーザーを検索するクエリがあるかもしれません。インデックスがない場合、クエリはテーブル全体を検索して正しいレコードを見つけます。代わりに、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を使用している場合は、パフォーマンスと最適化に関するドキュメントでクエリの測定と最適化の方法について学ぶことができます。