Chapter 08

アプリケーションコードの修正

hmatsu47
hmatsu47
2022.07.28に更新

この章について

v1 → v3 変更点の調査結果をもとに、アプリケーションコードの修正対象になりやすい点を示します。

アプリケーションコードの修正対象になりやすい変更点

すべてをカバーするものではありませんが、いくつかピックアップしていきます。

ライブラリ

DB 接続用のライブラリ(MySQL Connector の各言語対応版)を MySQL 8.0 対応バージョンに変更します。

その際、TLS 接続(TLS バージョンが合わない、非 SSL では接続できない等)の問題が生じる可能性がある点を留意しておきます。

TLS 接続の場合

TLS バージョンの問題が生じる可能性があります(Aurora MySQL 移行より前に新しいバージョンのライブラリに更新する場合)。

https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Security.html#AuroraMySQL.Security.SSL.TLS_Version

非 TLS 接続の場合

ライブラリのバージョンによっては、接続パラメータで SSL/TLS の無効化が必要になる場合があります。

例)

  • MySQL Connector/J で、接続パラメータにsslMode=DISABLEDを(追加)指定する

https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-connp-props-security.html

その他

パラメータグループでデフォルトどおりexplicit_defaults_for_timestamp1(有効)を指定した状態で、

  • MySQL Connector/J のプリペアドステートメントを使って
  • NOT NULLかつDEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMPTIMESTAMPDATETIME列に対して
  • nullUPDATEしたとき

の挙動が、

  • Aurora MySQL v1・MySQL Connector/J 5.1 の組み合わせ:UPDATE時のタイムスタンプで更新
  • Aurora MySQL v3・MySQL Connector/J 8.0 の組み合わせ:「NOT NULL列にnullUPDATEすることはできない」旨のエラーが発生

のように変化するケースがあります。

同様の事象が発生した場合はnullではなくNOW()などでUPDATEする形に SQL 文(プリペアドステートメント)を書き換えます。

また、Connector/J 8.0.29 でrewriteBatchedStatements=trueのときにROW_COUNT()の結果が不正な事象も見つかっています(8.0.28 に戻して回避)。

予約語のバッティング

すでに使用しているテーブル名・カラム名などに新しく予約語となったキーワード(RANKなど)が含まれる場合は、前後を「`」で囲みます。

例)

  • 既存コードについてはバッティング箇所のみ直す(「`」で囲む)
  • 新規コードについてはバッティングの有無に関わらずデータベース(スキーマ)名・テーブル名・カラム名・インデックス名やエイリアスを「`」で囲む
    • .で連結する形式で書かれている箇所は必ずしも「`」で囲む必要がないが、ミス防止のため全て「`」で囲む

FOUND_ROWS()(およびSQL_CALC_FOUND_ROWS

ページャ機能の実装で使っていたケースが多いと思います。

先に改修してリリースすると v1 運用中に性能低下の恐れがあることなどから、v3 移行後に改修するのが妥当でしょう。

文字セット・照合順序の問題

utf8utf8mb3

utf8utf8mb3のエイリアス)が残っている場合は、移行前または移行後にutf8mb4に変更します。

その際、照合順序の選択に注意が必要です。utf8_general_ciを使っていた場合はutf8mb4_general_ciが一番近い挙動になりますが、4 バイトの文字が区別できない欠点もあります。

https://mita2db.hateblo.jp/entry/2020/12/07/000000

utf8mb4のデフォルト照合順序

v2(MySQL 5.7)までとは異なり、utf8mb4_0900_as_ciがデフォルトになります。

無意識にデフォルトの指定を使っていると不具合が生じる可能性があるので、可能な限り明示的に指定します。

データ型

YEAR(2)YEAR(4)FLOAT(M,D)DOUBLE(M,D)、数値データ型のZEROFILL属性などがありそうです。

中でもYEAR(2)はすでに廃止されているので移行前の修正が必要です。

GROUP BY 【列名】 ASC/DESC

GROUP BY 【列名】 ASC/DESCの形式で書かれているもの以上に、 暗黙の昇順ソートASCが省略されているもの)が多そうです。

これは見逃しやすいので注意が必要です。

ORDER BYを伴わないGROUP BYを含む SQL 文が、暗黙ソートを期待して書かれたものかどうかを必ず確認しましょう。

UNIONの構文解析と動作の変更

FOR UPDATEとの組み合わせがありそうです。

SELECT COUNT(*)が遅くなるケースがある

WHERE句やGROUP BY句のないテーブル全件のSELECT COUNT(*)は MySQL 8.0.14 からパラレル処理で高速化されたのですが、Aurora MySQL 3.02.0 時点ではある程度行数が多いテーブルでは CPU 使用率が 100% に到達するとともに、Aurora MySQL v2 以前と比べても時間が掛かるケースがあるようです。

https://zenn.dev/hmatsu47/articles/mysql80-count-slowdown#fnref-52c5-1

Aurora MySQL 独自の問題

参照専用(Reader)インスタンスでのCREATE TEMPORARY TABLE (AS SELECT)挙動変化

innodb_read_only1のときに InnoDB ストレージエンジンで一時(テンポラリ)テーブルが作成できなくなったのに伴い、Reader インスタンスでCREATE TEMPORARY TABLE … ENGINE=InnoDBを実行する場合は SQL モードNO_ENGINE_SUBSTITUTIONを無効にする必要があります。

ただしAS SELECT付きで実行する場合は SQL モードにかかわらずエラーになります。

そのため、Reader インスタンスでCREATE TEMPORARY TABLEを実行する場合はENGINE=InnoDBを削除しておくのが良いでしょう。