はじめに
初めまして、スタートアップでGoのバックエンドエンジニアをやっている大学3年生です。
今回の記事を書こうと思ったきっかけとして、オープンソース版Twitterである『misskey』のとあるissueで『slow query』が話題に上がる出来事がありました。それを受けて、自分でも理解度が浅かったのを自覚したのと、また丁度、最近、インターン先でSQLのパフォーマンスチューニングする機会を頂いたのが理由になります。
スロークエリとは?
まずスロークエリ(slow query)とは、実行時間が一定時間よりも遅い(0.5~2.0秒など)クエリのことを言います。その原因は多岐にわたり、データベースの設定、SQLクエリの書き方、インデックスの不適切な使用などが考えられます。これらの原因を分析、特定し、そして適切な対処をとることでパフォーマンスの改善が見込めます。
ボトルネックの特定
パフォーマンス問題を解決するためには、まずボトルネックとなっている部分、つまりパフォーマンスを落としている原因を特定することが重要です。スロークエリのボトルネックを特定するためには一般的に以下の手段があげられます。
- クエリログの分析:ほとんどのデータベースシステムでは、実行されたクエリとその実行時間を記録するロギング機能があります。特に、MySQLにはスロークエリログという、特定の閾値を超えて実行時間がかかったクエリを記録する機能が存在します。これらのログを分析することで、パフォーマンスを低下させている特定のクエリを見つけ出すことが可能です。
- EXPLAINの利用:SQLのEXPLAINコマンドは、クエリがどのように実行されるか(実行計画)を表示します。これにより、データベースがどのインデックスを使用しているのか、テーブルのどの部分をスキャンしているのか、クエリが内部でどのように動作しているのかを理解できます。これを利用して、パフォーマンスの低下を引き起こしている可能性のあるクエリの動作を確認し、改善の手がかりを探します。
- システムリソースのモニタリング:クエリの実行に影響を与えるのはSQL文だけでなく、ハードウェアやネットワークのリソースも関係する場合もあります。したがって、CPUの使用率、メモリの使用量、ディスクI/O、ネットワークの状態などをモニタリングすることも重要となります。
具体的な改善案
1.インデックス
パフォーマンスを向上させるための効果的な手段の一つは、データベースにおけるインデックスの使用です。インデックスは、特定のカラムを持つレコードを検索しやすくするための索引のようなもので、WHERE句や結合の条件、ORDER BY句の条件で対象のカラムを使用する場合に設定することが推奨されます。
ただし、インデックスはパフォーマンスを向上させる一方で、データを更新する際(挿入、更新、削除)にはオーバーヘッドを増加させます。これは、行の変更があるたびにインデックスも更新する必要があるからです。そのため、むやみにインデックスは設定せず、どのカラムに付けるのかは慎重に選ぶ必要があるとも言えます。
2. バルクインサート
バルクインサートは、大量のデータを一括で挿入する方法。クエリ発行回数を抑えることで挿入速度を下げたり、ネットワークの通信量の減少、トランザクション処理の効率化などのメリットがあります。ただし、大量のデータを扱うので、メモリ消費量が激しい点、複数インデックスの更新処理がある点は注意が必要となります。
3. SQLクエリの最適化
使用するSQLの書き方自体を最適化することでパフォーマンスを改善することができます。たとえば、不要な結合を省く、WHERE句での条件指定を最適化する、LIMIT句を使用して必要な結果のみを取得するなどがあります。
4. 非正規化
非正規化とは、パフォーマンスを上げるためにあえて「正規化を崩す」こと。これは、データの結合(JOIN)の回数を抑えて、必要なデータをまとめて取れるようにあえて冗長なテーブル設計にすることと言えるでしょう。例えば、JOINが複数必要なるかつ、カラムの数が少ないケースや読み取り回数が頻繁にあるケースなどで使用することがあります。ただし以下の記事ように、一度正規化の場合で検証してみることや、どうして非正規化したのかをドキュメントを残しすなど、明確な目的と根拠を持って非正規化する必要があるのかどうかを考える必要があると思います。
まとめ
以上がスロークエリの原因と対策の概要です。これらのポイントを抑えて、データベースのパフォーマンス改善に取り組むことが重要です。ただし、具体的なケースによっては他にも注意すべきポイントが存在する場合がありますので、状況に応じて適切な対策を検討してください。
なお、最近は便利なORMフレームワークなどによって、クエリ最適化の自動化が進んでいますが、根本的な原理を理解し、パフォーマンスの改善に取り組むことは依然として重要かと思います。(ちなみに、今回初めての技術ブログ投稿で、まだまだ至らない点はあるかと思いますが、いいねでご応援いただけると嬉しいです!)