😇

何もしてないのに突然クエリが遅くなった時の対処方法

2023/10/04に公開

はじめに

アイスタイルDBREのsuzukitoです。
数年ぶりに「なんにもしてないのに突然クエリが遅くなる現象」に遭遇したので、いつもやっている対処方法をまとめてみました。

こんなことがあります

何もしてないのにクエリが突然遅くなった!
DBサーバーのCPU使用率が100%になって、クエリが滞留しまくっているぞ!

ちゃんとインデックスも作ってあるから、今日の午前中まで何も問題が起きてなかったのに。
最近リリースもしてないし、本当に何もしてない。

どうしたらいいんだろう。

まずはこれをお試し下さい

統計情報の更新をやってみましょう。
インデックスを使用しない実行計画が生成されている可能性が高いです。

遅くなったクエリが特定できている場合は、EXPLAINで実行計画を確認すると良いです。統計情報更新効果の有無がはっきりします。

統計情報の更新方法

MySQL

https://dev.mysql.com/doc/refman/8.0/ja/analyze-table.html

クエリが特定できて、テーブル名が分かっている場合

ANALYZE TABLE tbl_name

テーブル名が分からない場合

ANALYZE TABLE文を生成するクエリを実行して、生成されたクエリを実行します。

SELECT 
    CONCAT('ANALYZE TABLE ', table_name, ';') AS stmt
FROM
    information_schema.tables
WHERE
    table_schema = DATABASE()
AND table_type = 'BASE TABLE'

上記クエリを実行すると次の様な結果が出力されるので、コピーして実行します。

+-------------------------------------------+
| stmt                                      |
+-------------------------------------------+
| ANALYZE TABLE actor;                      |
| ANALYZE TABLE actor_info;                 |
| ANALYZE TABLE address;                    |
| ANALYZE TABLE category;                   |
~中略~
| ANALYZE TABLE city;                       |
| ANALYZE TABLE staff;                      |
| ANALYZE TABLE staff_list;                 |
| ANALYZE TABLE store;                      |
+-------------------------------------------+

SQL Server

クエリが特定できて、テーブル名が分かっている場合

https://learn.microsoft.com/ja-jp/sql/t-sql/statements/update-statistics-transact-sql?view=sql-server-ver16

UPDATE STATISTICS table_or_indexed_view_name

テーブル名が分からない場合

全テーブルの統計情報を更新するストアドプロシージャを実行します。
https://learn.microsoft.com/ja-jp/sql/relational-databases/system-stored-procedures/sp-updatestats-transact-sql?view=sql-server-ver16

EXEC sp_updatestats

PostgreSQL

https://www.postgresql.jp/document/15/html/sql-analyze.html

クエリが特定できて、テーブル名が分かっている場合

ANALYZE table_and_columns

テーブル名が分からない場合

テーブル名を省略すると、全テーブルを対象にします。

ANALYZE

これでダメだったらどうしたらいいの?

おそらくデータ量が増えて、本当にクエリが遅くなったんだと思われます。
遅いクエリを特定して実行計画を確認し、クエリに対応するインデックスを作成しましょう。
作成済みのインデックスが検索列だけを指定している場合は、カバリングインデックスの作成を検討してみて下さい。

https://dev.mysql.com/doc/refman/8.0/ja/optimizing-innodb-queries.html

https://learn.microsoft.com/ja-jp/sql/relational-databases/indexes/create-indexes-with-included-columns?view=sql-server-ver16

https://www.postgresql.jp/document/15/html/indexes-index-only-scans.html

なんでこうなるの?

なんででしょうね?
発生したときは障害になっているため、すぐに対処する必要があり、原因調査までしていません。数百台のDBサーバーを管理していますが、数年に一回程度の頻度で経験しています。

統計情報はRDBMSがクエリの実行計画を生成する際に参照する情報です。
ほとんどのRDBMSでは、テーブル行の一定以上の割合が更新されると自動的に更新されるようになっています。
また、テーブルの行数が多くなると、実行計画の自動更新が行われるような割合の更新が発生しにくくなるので、バッチで定期的に統計情報を更新させる運用をする場合もあります。

テーブル内のデータの分布が分からないと適切な実行計画が生成できないので、統計情報の更新は基本的に正しい行為だと思います。
が、ごくまれに、統計情報の更新が原因で実行計画が都合の悪い方に変わる事があります。

そんな、まれな状況に遭遇したら、まずは統計情報を手動で更新してみることをオススメします!

株式会社アイスタイル

Discussion