はじめに
この記事は MySQL Advent Calendar 2024 18日目の記事です。
INSTANT DDLを64回したらテーブル再構築が必要
INSTANT DDL操作がサポートされていても、INSTANTスキーマ変更の操作回数には上限があります。テーブル毎に計64回のINSTANTスキーマ変更に対応しており、この上限に到達したらテーブルの再構築が必要になります。
なにやら不穏な話が聞こえてきますね。
これは以下のOracleブログに書かれている話です。
INSTANT DDL操作を用いたMySQL InnoDBのスキーマ変更
つまりどんな話?
主にカラム追加時ですが、ALTER TABLE文でALGORITHM=INSTANT句を使って高速にDDL実行を完了することができます。これはINSTANT DDLという機能です。
これを行える回数に制限があることをご存じでしたか?
それが64回までという話です。
The maximum number of row versions permitted is 64, as each row version requires additional space for table metadata.
65回目を行いたい場合、テーブルの再構築が必要になります。
今まで何回やったかどうやって確認するの?
INFORMATION_SCHEMA.INNODB_TABLESテーブルのTOTAL_ROW_VERSIONSカラムで確認することができます。
mysql> SELECT NAME, TOTAL_ROW_VERSIONS FROM INFORMATION_SCHEMA.INNODB_TABLES
WHERE NAME LIKE 'test/t1';
+---------+--------------------+
| NAME | TOTAL_ROW_VERSIONS |
+---------+--------------------+
| test/t1 | 0 |
+---------+--------------------+
この例はまだ一回もやってないので0になってますが、例えば自分の実行した例だと、

6って出てますよね。
エラーメッセージ
こんなんが出ます。
MySQL Error (4092): Maximum row versions reached for table <db_name>/<table_name>. No more columns can be added or dropped instantly. Please use COPY/INPLACE.
テーブル再構築って?
大丈夫です、DROP & IMPORTし直せって話じゃありません。
OPTIMIZE TABLE または ALTER TABLE ... ENGINE=InnoDB を実行すればOKです。
OPTIMIZE TABLEって内部でANALYZE TABLEとALTER TABLE ... ENGINE=InnoDBを行っているので、要するにALTER TABLE ... ENGINE=InnoDBをやれって話です。
65回も同じテーブルにカラム追加するんですから、一回くらいOPTIMIZE TABLEやALTER TABLE ... ENGINE=InnoDBしてデータを綺麗に並べ替えとくのも良いですよね?
ちなみに9.1からは255回まで行ける
The maximum number of row versions permitted is 255 in MySQL 9.1.0 and later, as each row version requires additional space for table metadata. https://dev.mysql.com/doc/refman/9.1/en/innodb-online-ddl-operations.html#online-ddl-column-operations
dict0mem.hにそれはある
const uint8_t MAX_ROW_VERSION = 64
Maximum number of rows version allowed when columns are added/dropped INSTANTly.
After this limit is reached, any attempt to do ADD/DROP INSTANT column will result in error.
このMAX_ROW_VERSIONの数を超えてInstant DDLを実行するとコけるよとありますね。
https://dev.mysql.com/doc/dev/mysql-server/8.0.40/dict0mem_8h.html#a127c70e6c84930312e47d93dcfaa5609
9.1では255に増えてます。
const uint8_t MAX_ROW_VERSION = 255
https://dev.mysql.com/doc/dev/mysql-server/9.1.0/rem0types_8h.html#a127c70e6c84930312e47d93dcfaa5609
試してみた
については既に前述のブログ内で書かれてますんで、そっちを参照してください。
なんでこんな仕様に?
軽く調べてみましたが。わかりません。
65回も実行してる間にALTER TABLE ... ENGINE=InnoDB一回くらいやっとけや、って言うことなんですかね。
いや、それにしてもサラッと変な制限入れてるなあと。
終わりに
意外と知られてない(長時間運用しててやっと気づく)躓きポイントについて書いてみました。
ブログに書かれているんで、既に公にはなってるんですが、こういうのは何度言ってもいいと思いますしね。
明日は @asahide さんです。ポケGO仲間ですが、実は直でお会いしたことは無いんですw(いつかポケモン交換したいなあ)