
はじめに
コミューン株式会社 Tech & Platformチームの磯村(@isomura_hiroshi)です。 弊社のサービス Commune では長らくMySQL 5.7を使用していましたが、2025年6月にようやくMySQL 8へのメジャーバージョンのアップグレードを完了しました。 私たちが利用しているGoogle CloudのCloud SQL MySQL 5.7は2025年5月から有償サポート扱いとなり追加料金が発生するようになりました。 この費用を減らすために更新を決断しました。
更新の準備は主にインフラチーム主導で行われましたがアプリケーションエンジニアとしてもアップグレードを安全に行うために 本番環境で実際に実行されたクエリを使って検証を行い、確認できた問題に対して対策を行いました。 この記事ではこの検証を行った理由、結果、感想について共有します。
検証を行った理由
弊社では単体テストだけでなくDBをつかったテストコードも書いています。 このテストコードの実行時に利用するDBをMySQL8に更新するだけでもある程度問題が見つかりました。 しかしCommuneではDBが関係するロジックを全てテストで網羅できてはいません。 テストコードも順次書いていますが短期間で全てを網羅することは難しいためテストコード以外の検証方法が必要でした。
加えてMySQLの振る舞いが変わらなかった場合でもオプティマイザの変更によって クエリ実行時に作成される実行計画が変わることでパフォーマンスが悪化する可能性もあります。 このパフォーマンスの悪化もテストコードでは検知が難しいため検証を行う必要がありました。
検証方法
検証の方針
本番環境DBのクローンとクローンのMySQLをMySQL8にアップグレードしたDBを用意し、実際に実行されたクエリをそれぞれのDBに対して実行して結果を比較しました。 実際にアップグレードを行う際にはアプリケーションコードは一切変更しないため、アップグレードによるアプリケーションへの影響を事前に把握できます。

実施手順
1. 本番環境のクエリログを収集
検証用のクエリは本番環境で実行された平日日中の1時間分のSELECT文のクエリのログとしました。 SELECT文のみを対象としたのはSELECT文が圧倒的に実行数が多いこと、更新系クエリに比べて複雑なWHERE句が利用される 傾向があることで本番環境にしかないデータによる影響を受け易いことから差分が出る可能性が大きいと考えたためです。 また、更新系クエリは結果の評価を行うのが難しいことや一度検証を行ったらもう一度クローンを作成しなければいけないこと など実施のコストが大きいと考えたことも理由の一つです。
2. 検証環境の構築
検証用のDBは検証用のクエリを取得した時間帯の最後の時刻のスナップショットから作成しました。 存在しないデータに対するSELECT文の実行を減らすためです。 検証用のスクリプトはCommuneのサーバーと同じNode.jsとPrismaを使って作成しました。
3.1. クエリの実行と結果の差分の調査
各クエリをMySQL 5.7とMySQL 8.0の両方で実行して結果の差分を調査しました。
3.2. クエリの実行速度の調査
各クエリのExplain文をMySQL 5.7とMySQL 8.0で実行して実行計画の差分を調査しました。 実行計画に差分があったクエリをそれぞれのDBで5回ずつ実行して実行時間を比較しました。
先に実行計画の差分を調査したのは速度が変わる原因として実行計画の変更を想定していたこと、 それ以外の理由で速度が変わったとしても短期間での対処が困難だろうと判断したことによります。
検証とアップグレードに向けた準備
クエリの結果の差分
結果
詳細な数値をお伝えすることはできませんが、全体のリクエストのうち0.8%のリクエストで結果に差分が発生しました。 その全てが順序が変わったことによるもので、おおきく分けてORDER BYが指定されているクエリとされていないクエリの 2種類に分類することができました。
ORDER BYが指定されていないクエリで結果が変わったのは全てGROUP BYが使用されているクエリでした。 GROUP BYが使用されるクエリはMySQL 5.7において暗黙的に順序が保証される場合がありましたが、 MySQL8.0では暗黙的な順序が保証されなくなりました。このため結果が変わってしまったと考えられます。
ORDER BYが指定されているのに結果が変わってしまった理由はユニークでないカラムでソートしているためです。 ORDER BYで指定したカラムが重複した場合、MySQLは順序を保証しません。 MySQL5.7とMySQL8の内部でのロジックの変更により結果が変わってしまったと考えられます。
対策
ORDER BYが指定されていないクエリはもともとアプリケーション上で順序が重要でないからORDER BYが指定されていないと考えて アップグレードの差分の対策は行いませんでした。
ORDER BYが指定されているものの結果が完全に異なってしまうクエリに関しては クエリ毎に実行箇所の調査を行い、アプリケーションへの影響を確認しました。 ユーザーに影響が大きいと考えられるクエリに関してはビジネスサイドに相談を行った結果大きな問題はないと判断されました。 このため対策する必要はありませんでしたが、念のためアップグレード実施前にORDER BYのカラムにidを追加して 順序が完全に決定的になるようにアプリケーションに修正を加えました。 この挙動変更が問題になったとしてもアプリケーションの修正であれば対応が可能だからです。
クエリの実行速度の調査
結果
実行計画に差分があったクエリは全体の約1%でした。その中で実行速度が改善したのが約9%、悪化したのが2%、差分無しが89%でした。
対策
悪化したクエリは非常に少なかったですが、特に悪化率200%以上のクエリに限定するとほぼ1種類のクエリに限定することができたので このクエリに対してのみ対策を行いました。
実行計画の差分を確認したところもともとの実行計画に加えてカーディナリティが低いインデックスがindex_mergeで使用されるようになったことで 逆に速度が低下していたようでした。このため該当の低カーディナリティのインデックスを事前に削除しておくことでアップグレード後のパフォーマンス低下を防ぐことにしました。
これらの対策により、アップグレード後も安定したパフォーマンスを維持できることを確認しました。
終わりに
今回、本番環境で実行されたクエリを使ってMySQL 8.0へのアップグレードの検証を行いました。 この検証を行い発覚した問題も事前に対応しておいた結果、無事にアップグレードを完了することができました。
今回の検証を通じてアップグレードによって意外とDBの振る舞いが変わるということ、 そしてテストでなかなか検知しきれないということが認識できました。
検証を行う前はMySQL Shell Upgrade Checker Utility(MySQLの公式ツールで、アップグレード前の互換性チェックを行うユーティリティ)を使って事前に影響調査を行っているし DBを使った自動テストも通過しているのだから そうそう問題は起きないだろうと考えていました。 しかし実際には用意していた自動テストでは想定していなかったデータが本番には存在したため テストでは振る舞いが変わったことが検知できませんでした。
データベースのメジャーバージョンアップは特に慎重に行う必要があると理解できました。
今後もMySQL 8.4への更新など継続的なアップグレードが必要になります。 次回以降も安全にアップグレードを行うために今回実施した方法で検証を行おうと考えています。
コミューンでは、私たちと一緒に働く仲間を募集しています!少しでもコミューンの開発組織や職場環境に興味をお持ちの方、ぜひカジュアル面談でお話ししましょう。
https://open.talentio.com/r/1/c/commune/pages/108399/apply?token=0e6WjaZ62wkVoZ1XtgFduSzwPNHrKSR6