はじめに
こんにちは、介護/障害福祉事業者向け経営支援「カイポケ」の介護レセチームでエンジニアをしている沖口です。
チームで管理しているテーブルに長年の運用によりデータ量が相当数まで増えてきたものがあり、idカラムの型をINT UNSIGNEDからBIGINTに変更する必要がありました。 先日、その対応をAurora MySQLのBlueGreenDeployment(以降では省略してBlueGreenDeploymentと記載)を用いて短時間のメンテナンスで実現できたため、その事例を紹介します。
背景
カイポケは2011年にリニューアルを行い、現在のカイポケとしての運用を開始しました。 当時作成された一部のテーブルでは2011年から現在までデータの蓄積が続いており、今回対応を行った利用者の請求明細に関するテーブルは、INT UNSIGNEDの上限である約42億レコードに近々到達することがわかっていました。 レコード数がこの上限に達してしまった場合、利用者請求に関連する業務上極めて重要な機能が停止します。
これを未然に防ぐため、大規模なレコードが存在するテーブルの型変更について、実現方法の検討を行うことから始めました。
実現方法の検討
まずidカラムの型変更を行う方法について、生成AIのDeepResearchにより取りうる選択肢を調査しました。
- 直接ALTER TABLEを実行する
- オンラインスキーマ変更ツールgh-ost (GitHub's Online Schema Transmogrifier/Translator/Transformer/Transfigurator)を利用する
- オンラインスキーマ変更ツールpt-online-schema-changeを利用する
- BlueGreenDeploymentによるデプロイを行う
選択肢と特徴について把握した後は、実際に私たちのテーブルに適用する場合の制約と照らし合わせてよりベストな方法を検討します。
そこからは、DeepResearchの調査文章を鵜呑みにするのではなく、DeepResearchが根拠資料として出力した公式資料を確認しながら詰めていきました。
以下では、それぞれの選択肢についての判断結果と、その理由を書いていきます。
(見送り) 直接ALTER TABLEを実行する
MySQLはテーブルの型変更を行う場合、オンラインDDLによる顧客影響のない形でスキーマ変更を行うことはできません。*1
もし本番環境でDDLを開始した場合はDDLが完了するまでの間SHARED_UPGRADABLEロックが取得されます。
ユーザーの視点に立つと、利用者請求の変更に関する操作を行うと処理が完了せず、タイムアウトすることになります。
それを防ぐためにはメンテナンスの時間をとってリリースを行うことになりますが、その妥当性を検討しておかなければなりません。
私たちのメンテナンスモード下でのリリースには以下の制約があります。
- 介護事業者は日中は常に重要な業務を行っています。ログアウトが発生するリリースは利用率が下がった19時以降に行う必要があります。
- 介護事業者の中には19時から24時近くまで業務を行っている方もいます。メンテナンスを行う場合はより短い時間で行う必要があります。
- 私たちのチームも継続可能な開発体制の一環として、休日深夜のリリースは極力避けるべきという考えがあります。
これらの制約を基に、この手法については「リリース作業が2、3時間程度で完了するか否か」を1つの判断基準として調査することにしました。
そこで、試しに本番環境のAurora MySQLインスタンスをコピーした疑似環境を用意し、実際に流したいDDLを実行しました。 結果として実行時間は7時間弱となり、判断基準とした時間より上回ったため、この選択肢は除外することになりました。
(見送り) gh-ost
gh-ostはGitHubが提供する、オンラインでスキーマ変更を行うことができるツールです。(ツール自体の説明は割愛します)
オンラインでスキーマ変更を行うことができるのであればメンテナンス時間も不要となり、サービスを止めることなく型の変更ができそうです。
しかし、実行するための制約を確認したところ、対象テーブルに外部キー制約がある場合はサポート外との記載があり、今回のケースとマッチしなかったため見送ることとなりました。
(見送り) pt-online-schema-change
Perconaが提供する、MySQLのスキーマ変更をオンラインで実行するためのツールです。(こちらも、ツール自体の説明は割愛します)
pt-online-schema-changeには、私たちに関係する部分としては以下の特徴があります。
- トリガー作成に伴うデータコピー負荷の増加
- 負荷が大きいとツールが判断した場合の処理停止と再開
上記は注意事項ではありますが、これらによってpt-online-schema-changeの使用が不可能であるとの判断はしませんでした。 一方、懸念点としては以下がありました。
- トリガー作成による負荷検証を検討・実施する必要がある。
- pt-online-schema-changeによるリリースを開始した後、リリース完了となる時刻が不明であり体制を作りづらく、深夜待機に発展する可能性もある。
- pt-online-schema-changeによるリリース実施経験がなく、リリース中断時に元の状況にロールバックする方法の検討/再検討の可能性がある。
上記の懸念点がBlueGreenDeploymentの場合は抑えられると判断し、結果としてpt-online-schema-changeは見送ることにしました。
(採用) BlueGreenDeployment
BlueGreenDeploymentで対処する場合、以下の流れで作業することになります。
- 本番で稼働しているBlue環境を元にGreen環境を作成
- Blue環境へのデータ変更は、binlogを用いてGreen環境に継続的にレプリケーションされる
- Green環境に対して変更を実施
- Blue環境とGreen環境を入れ替えることで変更の適用完了
もし、BlueGreenDeploymentの制約が今回のテーブル変更に影響しない場合には、以下が言えます。
- 本番環境に影響しない形でリリースとは分離してDDLを事前実行できる
- Green環境へのDDL実行時間中には、本番環境への影響がないため体制を張る必要がない
- 予定より長時間となった場合もDDL実行日とリリース日の間にバッファをもうけておくことでリリースに影響を出さずに済む
- リリース可否の判断が明確。リリース可能と判断した後はBlue環境とGreen環境を入れ替えるだけであり問題が発生しにくい
- Green環境へのDDLが成功した場合はリリース可能
- 失敗した場合はリリース不可
- メンテナンスはBlue環境とGreen環境を入れ替えるタイミングのみ必要であり、1時間もかからず完了できる見込み
こういった変更の確実性の高さとリリースまでの予測の立てやすさから、この手法を最優先で検討することにしました。
BlueGreenDeploymentの調査
まずはBlueGreenDeploymentを用いる場合の制約について公式ドキュメントを確認します。
公式ドキュメントに記載されている内容の中で見落としがないよう、全て読みました。
ここでユースケースとしてスキーマ変更についての記載があると一気に実現の可能性が高まるのですが、公式ドキュメントではパッチや設定値変更についてのユースケースが勧められている程度でスキーマ変更については記載がありませんでした。
Amazon RDS ブルー/グリーンデプロイを使用する利点
Amazon RDS ブルー/グリーンデプロイを使用すると、セキュリティパッチを最新の状態に保ち、データベースのパフォーマンスを向上させ、短い予測可能なダウンタイムで新しいデータベース機能を導入できます。ブルー/グリーンデプロイでは、エンジンのメジャーバージョンまたはマイナーバージョンのアップグレードなど、データベース更新のリスクとダウンタイムが軽減されます。
しかし、ブルー/グリーンデプロイの一般的なベストプラクティスには、制約事項の形で以下の文言がありました。
ブルー/グリーンデプロイを使用してスキーマの変更を実装する場合は、レプリケーション互換の変更のみを行ってください。 例えば、ブルーデプロイからグリーンデプロイへのレプリケーションを中断することなく、テーブルの最後に新しい列を追加することができます。ただし、列名の変更やテーブル名の変更などのスキーマの変更は、グリーンデプロイへのレプリケーションを中断させます。 レプリケーションと互換性のある変更の詳細については、MySQLドキュメントの「ソースとレプリカのテーブル定義が異なるレプリケーション」とPostgreSQL論理レプリケーションドキュメントの「制限」を参照してください。
この制約は裏を返せば「その変更がレプリケーション互換であればスキーマ変更に利用可能である」と解釈できます。 MySQLのドキュメントを見てみましょう。
17.5.1.9.2 データ型が異なるカラムのレプリケーション
ソース上の対応するカラムと同じテーブルのレプリカコピーは、同じデータ型であることが理想的です。ただし、特定の条件が満たされているかぎり、これは必ずしも厳密には強制されません。 通常、特定のデータ型のカラムから、同じサイズまたは幅 (該当する場合) またはそれ以上の同じ型の別のカラムにレプリケートできます。
サポートされる変換.違うけれども似ているデータ型の間でサポートされる変換を次のリストに示します。 整数型TINYINT、SMALLINT、MEDIUMINT、INT、およびBIGINTのいずれかの間。 これには、これらの型の符号付きおよび符号なしバージョンの間の変換が含まれます。 不可逆変換は、ソース値をターゲットカラムで許可される最大値 (または最小値) に切り捨てることで行われます。符号なし型から符号付き型への変換時に非可逆変換を保証するには、ターゲットカラムがソースカラムの値の範囲を収容できる十分な大きさである必要があります。たとえば、TINYINT UNSIGNEDは、非不可逆にSMALLINTに降格できますが、TINYINTにはできません。
上記の内容から、カラム型のINT UNSIGNEDからBIGINTへの昇格はレプリケーション互換であることがわかったため、サポート対象と判断しました。
Amazon Aurora のブルー/グリーンデプロイの制限と考慮事項にも今回のスキーマ変更に影響する制約はなかったため、ここまでの調査およびメリットの高さからBlueGreenDeploymentの採用を決めました。
本番環境でのリリース
スケジュール

BlueGreenDeploymentの本番環境適用とメンテナンス(本番リリース)は数日空けて計画しました。
このスケジュールでは、以下を考慮しています。
- DDL実行時間が事前計測よりも長くかかる可能性への備え
- DDLが実行された後、Blue環境で実行されたクエリがGreen環境に後追いで適用されるレプリケーション処理時間への考慮
- 不測の事態が発生した場合のリカバリー時間
特に不測の事態への備えについては、BlueGreenDeploymentによるDDL実行について公開されている事例が少ないことから、何かエッジケースを踏む可能性があったので設定しました。
後続で書きますが、不測の事態が実際に発生しており、時間ギリギリでリカバリーに成功したためバッファを設けておいてよかったです。
実行時間
本番での実測値は以下の通りで、無事1時間のメンテナンスでリリースを完了することができました。
- Aurora MySQL
- DBインスタンス: db.r6i.16xlarge
- 変更対象テーブルのレコード数: 2,574,439,006レコード
- DDLの実行時間
- 9時間30分
- メンテナンス時のBlueとGreenの入れ替え作業
- 10分ほど(※正確な記録を取り忘れました)
- メンテナンス全体
- 1時間
以降は、本番環境で起きた不測の事態について書いていきます。
本番環境での不測の事態: データ不整合が発生しDDL実行後のレプリケーションが失敗する
起きたこと
Green環境を作成し、Green環境へDDLの実行を行って無事完了したのですが、DDLの実行が完了した後に行われるレプリケーションでエラーが発生していました。
エラーメッセージ
2025-11-18T01:14:43.909892Z 7858 [ERROR] [MY-010584] [Repl] Replica SQL for channel '': Worker 1 failed executing transaction 'ANONYMOUS' at source log , end_log_pos 54575012; Could not execute Delete_rows event on table {テーブル名}; Can't find record in {テーブル名}, Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's source log mysql-bin-changelog.038641, end_log_pos 54575012, Error_code: MY-001032
これはBlue環境で実行されたdeleteクエリをGreen環境に適用しようとした際に、delete対象のレコードが無いぞと言っています。
エラーが発生している削除対象の該当行が存在するか、Green環境へSELECTクエリを実行したのですが、しっかりと存在するので不可解なエラーメッセージで困惑です😇
原因
以下はレプリケーションに利用されるbinlogから、DELETEに失敗したlogを抜粋したものです。
### DELETE FROM `{テーブル名}`
### WHERE
### @1=-824762424 (3470204872) /* INT meta=0 nullable=0 is_null=0 */
### @2=NULL /* DATE meta=0 nullable=1 is_null=1 */
### @3=NULL /* TIME(0) meta=0 nullable=1 is_null=1 */
### @4=NULL /* TIME(0) meta=0 nullable=1 is_null=1 */
### @5='05' /* STRING(8) meta=65032 nullable=1 is_null=0 */
「@X」の次にあるのは実際に入る値で、たとえば @5 、つまり5番目のカラムに入るのは '05' であることがわかります。
このうち、 @1 は今回型変更を行ったカラムです。Blue環境ではINT UNSIGNED、Green環境ではBIGINTというように型が異なります。
@1 の値として書かれている -824762424 (3470204872) は他と表記が異なりますが、以下のように読み取ることができます。
-824762424: signed解釈の値(3470204872): unsigned解釈の値
INT UNSIGNEDのカラムに対してSQL上で使われるのはunsigned解釈の値なので delete from {テーブル名} where id = 3470204872 はHITします。
一方でGreen側はこのbinlogを用いてレプリケーションを実行していく際、どうやら -824762424 が値として扱われるよう解釈してしまっているようでした。
つまり、Blue側は delete from {テーブル名} where id = 3470204872 を行っていましたが、情報を伝搬されたGreen側は delete from {テーブル名} where id = -824762424 を行っていました。しかしそのような行は存在しないため、レプリケーションエラーが発生していたのです。
調査の過程
今回は一度の実行が長時間となるDDLを用いたリリースであるということから、探索的に成功するまで実験を繰り返すような対処法の探し方はできず、限られた時間で確実性の高い対処法を探し出し、一度の成功でリカバリーをする必要がありました。
そのため、仮説を持って確実性の高い証拠・裏どりを探しに行く動きをとっています。
(仮説1)binlogを確認する前、「行は存在するのに削除対象が見つけられない」という状況から
- Green環境の型変換後のid:
1(BIGINT) - binlogレプリケーションにおけるクエリの履歴である
delete from {テーブル名} where id = 1 (INT UNSIGNED)
ともに値は 1 ではありますが、内部的に別物となり一致しない状態になっているのではないか?という仮説を持ちました。
(仮説2)仮説1を念頭にbinlogを確認したところ、id列に -824762424 と (3470204872) の2値が併記されており、本来扱うべきである 3470204872 ではなく -824762424 がwhere句で使われているのでは、と初期の仮説1から別仮説に一歩進展しました。
裏付け
仮説2をドキュメントで確認できれば確度が上がると考え、レプリケーション時の値の解釈についてMySQLの公式ドキュメントを再確認しました。 すると、ソースとレプリカで異なるテーブル定義を使用したレプリケーションにて、以下のオプション記載を見つけました。
ALL_SIGNED
昇格される整数型を符号付き値として扱います (デフォルト動作)。ALL_UNSIGNED
昇格される整数型を符号なし値として扱います。整数型が昇格されるときに、符号ありか符号なしかは保持されません。デフォルトでは、レプリカはこのような値をすべて符号付きとして扱います。
これは、今回変更したカラムの値はデフォルトでは符号付き値 (-824762424) として扱われることを示しています。また、ALL_UNSIGNED を指定することで符号なし値 (3470204872) として扱われるように設定できるともあります。
今回の場合はまさにこれが対処法となりそうで、「これだ!」と仮説が確信に変わりました。
ドキュメントの該当部分は事前に読んでいたのですが、このような事態につながる記載であるとは気付けませんでした。
さらなる裏付け
id列がsigned解釈の値であるという場合、delete / updateをしようとすれば対象の行が見つからないエラーとなりますが、insertの場合はエラーなくマイナスの値でinsertされた行があるはずです。
実際に確認したところ、Green環境にはマイナス値のid列が多数作成されており、確証を得ることができました。

リカバリー
リカバリーのためには ALL_UNSIGNEDを付与したGreen環境で再度レプリケーションを実行する必要があり、以下のように全工程のやり直しを行いました。
- Green環境の削除
- Green環境の再作成
ALL_UNSIGNEDパラメータの追加- DDLの再実行
幸いエラーが発生した当日に原因と対処法の特定ができたため、リリース実行日に間に合わせることができました。
終わりに
今回はBlueGreenDeploymentを活用したカラム型の変更と、その際に生じた予期せぬレプリケーションエラーについて記載しました。
予期せぬ事態は1件発生してしまいましたが、
- 顧客影響を出さず、実行時間を気にせずDDLを本番実行できる
- Green環境の型変更が正常に完了できればメンテナンスは不安なくリリースができる
- 短時間のメンテナンスにより介護事業者がアプリを利用できない時間を短時間としつつ、リリース関係者も無理なくリリースができる
というBlueGreenDeploymentのメリットを活かしたリリースが行えたと思います。
この記事がこれからスキーマ変更を行う方の役に立つと嬉しいです。
読んでいただきありがとうございました。
*1:オンラインDDL操作に関する公式ドキュメント: https://dev.mysql.com/doc/refman/8.0/ja/innodb-online-ddl-operations.html