MySQLを運用していると、「ページの読み込みが遅い」「サーバーの負荷が急に上がった」といった問題に直面することがあります。その原因の多くは、実行に時間がかかるSQL、いわゆるスロークエリにあるといえるでしょう。スロークエリを放置すると、ユーザー体験の悪化だけでなく、売上機会の損失やインフラコストの増大にもつながりかねません。本記事では、スロークエリの基本的な仕組みから、検出・解析・改善までの一連の流れを体系的に解説していきます。MySQL運用に悩んでいる方、外部サポートを検討している方にとって、実践的なヒントになれば幸いです。
MySQLのスロークエリとは?初心者にもわかりやすく仕組みを解説
データベースのパフォーマンス問題を理解するには、まずスロークエリの基本を押さえることが大切です。ここでは、スロークエリとは何か、どんな症状として現れるのか、そしてなぜ発生するのかを、初心者の方にもわかりやすく整理して見ていきましょう。
スロークエリの定義(遅いクエリとは何か)
スロークエリとは、MySQLで実行に時間がかかったSQLのうち、long_query_time や min_examined_row_limit などの条件を満たしてスロークエリログに記録されるクエリを指します。
long_query_time のデフォルト値は10秒ですが、実運用では要件に応じてより短く設定することもあります。
スロークエリが増えると、ページ表示の遅延、タイムアウト、CPUやI/O負荷の上昇などにつながることがあります。
主な原因としては、インデックス不足、フルテーブルスキャン、非効率な結合、データ量の増加などが挙げられます。
よくある症状(ページが遅い・高負荷・CPU/IO増加)
スロークエリが発生すると、いくつかの典型的な症状が現れます。ユーザーから見ると、Webページの表示が遅くなったり、処理がタイムアウトしたりといった形で影響を受けることになるでしょう。
サーバー側では、CPU使用率やI/O負荷が急激に上昇するパターンがよく見られます。特に、特定の時間帯だけ負荷が高くなるような場合は、その時間帯に実行されているクエリを重点的に調べてみると、原因が見つかることが多いものです。接続プールを使用している環境では、スロークエリが接続を長時間占有し、他のリクエストが待たされるという連鎖的な問題も起きやすくなります。
スロークエリが発生する主な原因一覧(インデックス漏れ/フルスキャン/結合ミス/データ量増加)
スロークエリの原因は多岐にわたりますが、代表的なものをいくつか挙げてみましょう。最も多いのは、WHERE句やJOIN条件に適切なインデックスが設定されていないケースで、これによりテーブル全体を走査するフルスキャンが発生します。
また、複数テーブルの結合順序が最適でなかったり、SELECT *で不要なカラムまで取得していたりすることも、パフォーマンス低下の原因となります。さらに見落としがちなのが、データ量の増加による影響です。開発時には問題なかったクエリも、本番環境でデータが増えるにつれて急激に遅くなることがあり、定期的な見直しが欠かせません。
MySQLでスロークエリの検出
問題を解決するには、まず問題を見つけることから始まります。MySQLには、スロークエリを検出するための機能がいくつか用意されています。
スロークエリログの有効化と設定確認
スロークエリログを使うには、まずこの機能を有効にする必要があります。MySQLの設定ファイル(my.cnf または my.ini)に記述するか、実行中のサーバーに対してSQLコマンドで設定を変更できます。
現在の設定を確認するには、SHOW VARIABLES が使えます。たとえば SHOW VARIABLES LIKE ‘slow_query%’ でログの有効化状況や出力先、SHOW VARIABLES LIKE ‘long_query_time’ でしきい値を確認できます。
slow_query_logがONになっていれば有効化されており、slow_query_log_fileでログファイルの出力先を確認できるでしょう。設定変更後は、意図通りにログが出力されているかを実際に確認することをおすすめします。
ログ出力閾値とログフォーマット
どのくらいの実行時間をスローとみなすかは、long_query_time で指定します。値は秒ベースですが、より細かい精度でも設定できます。Webアプリケーションであれば1秒、よりシビアな環境では0.5秒や0.1秒に設定することもあるでしょう。
ログには実行時刻、ユーザー名とホスト、クエリの実行時間、ロック待ち時間、クライアントに返した行数、走査した行数、そして実際のSQL文が記録されます。これらの情報から、「本当に遅いのか」「ロックが原因なのか」「スキャン行数が多すぎるのか」といった判断ができるようになります。
ログ集計ツールの使い方(mysqldumpslowとpt-query-digest)
ログファイルが大きくなると、手作業での分析は現実的ではなくなってきます。MySQLには標準でmysqldumpslowというツールが付属しており、これを使えばログを集計してくれるので便利です。
より高度な分析を行いたい場合は、Percona社が提供するpt-query-digestが広く使われています。このツールは、類似クエリをグループ化して統計情報を出してくれるため、「どのパターンのクエリが全体のどれくらいの時間を占めているか」といった俯瞰的な分析が可能になるでしょう。
Performance Schemaによる収集
MySQL 5.6以降では、Performance Schemaという仕組みを使って、より詳細なパフォーマンス情報を収集できます。スロークエリログでは捉えきれない、待機イベントやI/O統計といった情報も取得可能です。
events_statements_summary_by_digestテーブルを参照すると、クエリパターンごとの実行回数や平均実行時間、合計実行時間などが確認できます。これにより、「1回あたりは速いけれど、大量に実行されているクエリ」といった、別の観点からの問題発見にも役立つでしょう。
ログ抽出コマンドの例
日常的な運用では、特定の条件に合致するログだけを抽出したいことがあります。grepコマンドと組み合わせて特定のテーブル名やキーワードを含むクエリを抽出したり、awkで実行時間が一定以上のものだけを取り出したりといった方法が有効です。
また、tail -fでリアルタイム監視を行いながら、問題が発生したタイミングでのクエリを確認するという運用も効果的です。ログ解析基盤を構築している環境であれば、Grokパターンでログを構造化し、ダッシュボードで可視化する方法も一般的になっています。
MySQLのスロークエリの解析と対処
問題となるクエリを特定できたら、次はその原因を深掘りして改善策を講じていきます。ここでは、具体的な解析手法と対処方法を見ていきましょう。
EXPLAINによる実行計画の確認
スロークエリの原因を探る際に、最も基本的かつ強力なツールがEXPLAINコマンドです。EXPLAIN を対象のSQLの前に付けて実行すると、MySQLがそのクエリをどのように処理する予定かを確認できます。特に SELECT の解析でよく使われます。」
出力結果で特に注目すべきは、type列とrows列、そしてExtra列でしょう。type列がALLになっていればフルテーブルスキャンが発生していることを意味し、インデックスが使われていない可能性が高いといえます。rows はオプティマイザによる推定値ですが、その値が大きい場合は、多くの行を読む実行計画になっている可能性があります。
インデックス診断と最適化
EXPLAINの結果を踏まえて、インデックスの追加や変更を検討します。WHERE句で頻繁に使われるカラムや、JOIN条件に指定されるカラムには、インデックスを設定することでクエリ速度が大幅に改善されることがあるでしょう。
複数のカラムを組み合わせた複合インデックスも有効な手段です。ただし、インデックスの追加はINSERTやUPDATEの処理速度に影響を与えるため、むやみに増やすのは避けるべきでしょう。必要なインデックスだけを適切に設計することが、バランスの取れたパフォーマンスチューニングにつながります。
スキーマ設計の見直し
クエリレベルの最適化では限界がある場合、テーブル設計自体を見直す必要が出てくることもあります。正規化が過度に進んでいると、多数のテーブルを結合する必要が生じ、それがパフォーマンスのボトルネックになりかねません。
逆に、読み取り性能を重視する場合は、あえて非正規化してデータを冗長に持たせるという選択肢もあるでしょう。また、大量のデータを扱うテーブルでは、パーティショニングによってアクセス範囲を限定することで、クエリ速度を改善できるケースもあります。
クエリリライトと結合順序の最適化
SQLの書き方によって実行計画が変わることがあります。サブクエリとJOINのどちらが有利かはケースによるため、EXPLAIN で確認しながら選ぶのが安全です。
MySQLのオプティマイザは賢いのですが、万能ではありません。テーブルの結合順序をSTRAIGHT_JOINで明示的に指定することで、性能が改善するケースも存在します。ただし、このような強制的な指定は、データ分布が変わると逆効果になることもあるため、慎重に判断する必要があるでしょう。
バッチ処理とトランザクションの最適化
大量のデータを一度に更新するバッチ処理は、スロークエリの温床になりやすいものです。1つの大きなトランザクションで全件を処理するのではなく、小さな単位に分割して処理することで、ロック時間を短縮できるでしょう。
また、長時間のトランザクションは他のクエリのロック待ちを引き起こす原因にもなります。トランザクションはできるだけ短く保つという原則を意識することが、全体的なパフォーマンス向上につながるといえます。
キャッシュとサーバー設定の調整
頻繁に実行される同じクエリに対しては、アプリケーション側でのキャッシュ導入が効果的です。Redisやmemcachedを使って結果をキャッシュすることで、データベースへのアクセス自体を減らせるでしょう。
MySQL側の設定としては、InnoDBバッファプールのサイズ調整が代表的なチューニングポイントです。十分なメモリを割り当てることで、ディスクI/Oを減らし、クエリ応答時間を短縮できます。ただし、これらのリソース調整は、クエリ最適化を行った後の手段として位置づけるのが一般的です。
変更検証と負荷試験
改善策を本番環境に適用する前に、必ず検証を行うことをおすすめします。ステージング環境でEXPLAINの結果を確認し、期待通りの実行計画になっているかを確かめましょう。
可能であれば、本番相当のデータ量で負荷試験を実施することも有効です。開発環境では高速だったクエリが、データ量が増えると急激に遅くなるというケースは珍しくありません。変更前後のパフォーマンスを定量的に比較できるようにしておくと、改善効果を客観的に評価できるでしょう。
スロークエリにお悩みなら、株式会社パソナデータ&デザインへご相談ください
スロークエリの改善は、単にSQLを書き換えるだけでは解決しないこともあります。
実際には、実行計画の確認、インデックス設計の見直し、MySQLの内部状態の調査、サーバー設定の調整など、複数の観点から原因を切り分けることが重要です。
パソナデータ&デザインの MySQLコンサルティングサービス では、MySQLのパフォーマンス改善をはじめ、ボトルネックの特定、スロークエリログや内部ステータスの分析、改善施策のレポート提出、必要に応じたチューニング実施まで支援しています。LP上でも、MySQLパフォーマンス改善、SQLチューニングやパラメータチューニングのアドバイス、スロークエリログの調査 などが案内されています。
「どのSQLが本当の原因かわからない」
「インデックスを追加してよいのか判断できない」
「調査はしているが、改善方針に自信が持てない」
そのような場合は、専門家に相談することで、原因の特定と改善を効率的に進めやすくなります。
MySQLの性能改善やスロークエリ対策をご検討中の方は、MySQLコンサルティングサービスをご覧ください。
まとめ
本記事では、MySQLのスロークエリについて、基本的な考え方から検出方法、解析・改善の進め方までを解説しました。
スロークエリは、Webアプリケーションのレスポンス低下やサーバー負荷の増大につながる重要な課題ですが、ログの確認や実行計画の分析を通じて、原因を整理しながら改善していくことが可能です。スロークエリログは long_query_time などの条件をもとに遅いクエリを記録し、Performance Schema ではクエリの実行状況をより詳細に把握できます。
- スロークエリは、MySQLで実行に時間がかかり、条件を満たしてスロークエリログに記録されるクエリのこと
- スロークエリログやPerformance Schemaを活用して、問題のあるクエリを特定することが改善の第一歩
- EXPLAIN による実行計画の確認と、インデックスの見直しが基本的な改善アプローチ
- クエリの書き方やトランザクション設計を見直すことで、さらなる性能改善につながる場合がある
- 自社だけで原因調査や改善が難しい場合は、専門家への相談も有効な選択肢
まずはスロークエリログやPerformance Schemaを活用し、どのクエリがボトルネックになっているのかを把握することから始めてみてください。
スロークエリの調査やMySQLの性能改善にお悩みの方は、MySQLコンサルティングサービスもご覧ください。


