MySQL8.0でSELECT COUNT(*)が低速になる動作は8.0.37で解消されていた!

メディア統括本部 サービスリライアビリティグループ(SRG)の鬼海雄太(@fat47)です。
#SRG(Service Reliability Group)は、主に弊社メディアサービスのインフラ周りを横断的にサポートしており、既存サービスの改善や新規立ち上げ、OSS貢献などを行っているグループです。
本記事は、MySQL8.0で有名なSELECT COUNT(*)が遅くなるという事象が、MySQL8.0.37で解消された話を書いています。
なにかの役に立てば幸いです。
 

MySQL8.0ではSELECT COUNT(*)が低速になる


MySQL8.0ではSELECT COUNT(*)が低速になるというのは有名な話です。
 
実際にAurora MySQL Version3(MySQL8.0互換)へのアップグレードを進めるなかで、この問題に遭遇したことが何度かあります。
今まではクエリを変更してSELECT COUNTの利用をやめるなり、アプリケーション側で対応を進める必要がありました。
しかし、MySQL8.0のリリースから数年、最新のMySQL8.0ではこの問題が解消されたようです。

MySQL8.0.37で低速なのが解消された!?


2024年4月にMySQL8.0.37はリリースされています。
ですが、リリースノートをいくら眺めてもSELECT COUNT(*)の挙動が解消された記述は一切ありません。
 
しかし、bugs.mysqlに2019年に投稿されたページを見てみますと、
Bug #97709 MySQL 8 Select Count(*) is very slow
 
2024年4月に以下の投稿がされています。
[30 Apr 16:31] MySQL Verification Team
📕
[30 Apr 16:31] MySQL検証チーム
フィードバックとテストケースをありがとうございます。 あなたが観測した劣化は、SELECT COUNT()がセカンダリインデックスの代わりにクラスタ化インデックスを使用していることが原因である可能性があります。 この問題は8.0.37のバグ#112767 SELECT COUNT()で修正しました。 8.0.37で試してみて、まだ問題に直面するようであれば、新しいバグを報告してください。
 
改めてリリースノートを見て、#112767の部分を見てみます。
InnoDB: MySQL no longer ignores the optimizer hint to use a secondary index scan, which instead forced a clustered (parallel) index scan. In addition, added the ability to provide an index hint that forces use of a clustered index. (Bug #100597, Bug #112767, Bug #31791868, Bug #35952353) References: This issue is a regression of: Bug #12978.
📕
InnoDB: MySQL はセカンダリ・インデックス・スキャンを使用するオプティマイザ・ヒントを無視しなくなった。さらに、クラスタ化インデックスの使用を強制するインデックスヒントを提供する機能が追加されました。(バグ#100597、バグ#112767、バグ#31791868、バグ#35952353) 参考文献 この問題はリグレッションです: Bug #12978のリグレッションです。
 
どうやらこの部分の修正でSELECT COUNT(*)の低速な部分が解消されているようです。

動作検証


再現検証は下記のbugs.mysqlの中に再現手順がありましたので、そちらの方法でおこないます。
 
テーブルの作成とデータの生成
 
このテーブルに対してSELECT COUNT(*)を実行すると、MySQL5.7では0.04秒程度で実行できていました。
 
MySQL8.0.28の環境では以下のように0.8秒(約20倍)かかるようになってしまいました。
 
これをMySQL8.0.36まで上げてみます。
これは2024年6月現在、最新のAurora MySQL3.07.0との互換バージョンとなります。
このバージョンでもSELECT COUNTは低速なままです。
 
MySQL8.0.37まで上げてみます。
2024年6月現在、このバージョン互換のAurora MySQLはリリースされていません。
レスポンスが高速になったことが確認できました。
 
なお、私が担当している実際のサービスでもSELECT COUNTの低速化が確認されており、
そちらではMySQL5.7では0.6秒程度だったが、MySQL8.0では38秒もかかるようになっており、
サービスの継続が困難な状態となっていました。
同様にこの環境もMySQL8.0.37にアップグレードしたところ、5.7相当にレスポンスが改善されたことが確認できました。
 

LTS MySQL8.4ではどうなの?


LTSのMySQL8.4のバージョンではこの改善は取り入れられているのでしょうか。
 
[16 Feb 22:07] Philip Olson
どうやら8.4にも改善は取り入れられていそうです。
 
リリースノートを確認してみると、ちゃんと同様の記述がありました。
InnoDB: MySQL no longer ignores the optimizer hint to use a secondary index scan, which instead forced a clustered (parallel) index scan. In addition, added the ability to provide an index hint that forces use of a clustered index. (Bug #100597, Bug #112767, Bug #31791868, Bug #35952353)
 
一応動作確認をしてみましたが、ちゃんと高速化されていました。

終わりに


MySQL8.0リリースから、SELECT COUNT(*)が低速になるのは有名な話でしたが、ようやくここに改善の手が入りました!
Aurora MySQLでは現時点で対応していないので、早く対応したバージョンがリリースされると嬉しいですね!
SRG では一緒に働く仲間を募集しています。 ご興味ありましたらぜひこちらからご連絡ください。
 
このエントリーをはてなブックマークに追加