単純なカラム追加をオンラインDDLで実行しようとするとエラーが発生した

MySQLのversionは8.0.19。

カラム追加のalter table文をalgorithm=inplace, lock=noneを指定してオンラインDDLで実行した。問題なく実施できると思ったが、以下のエラーが発生した。

[0A000][1846] ALGORITHM=INPLACE is not supported. Reason: INPLACE ADD or DROP of virtual columns cannot be combined with other ALTER TABLE actions. Try ALGORITHM=COPY.

virtual columnsと書かれているが、boolean NOT NULL DEFAULT falseである単純なカラムを追加しようとしているだけだった。

既存のテーブルのDDLを確認したところ、関数indexが定義されており、これが原因の可能性が高く見えた。

関数indexを削除してオンラインDDLを成功させる

関数indexはユニークキーのために作成しているもので、一時的にインデックス自体を削除してから、再度オンラインDDLを実行した。

今回のオンラインDDLは問題なく成功し、エラーの原因が関数indexにあることがわかった。

関数indexが実現しているユニークキーの機能を保ちつつオンラインDDLを実行する方法を考える。

Generated Columnの位置とカラム追加

関数indexがあるとカラム追加時のエラーにINPLACE ADD or DROP of virtual columnsという文言が出てくるため、関数indexで使用されている仮想列が暗黙でテーブルに追加されているのではないかと考えた。

information_schemaを見てみたが確かなことはわからなかったので、Generated Columnを定義した場合のカラム追加の挙動を確認した。

Generated Columnの後にカラム追加

テーブルtの先頭にgen_colというGenerated Columnを追加した。

alter table t
add gen_col boolean as (if(col, true, NULL)) before id;

その後、テーブル(の末尾)に普通のカラムを追加したところ、オンラインDDLで問題なく成功した。

Generated Columnの前にカラム追加

その次に、カラム追加する場所をGenerated Columnの前に指定して、オンラインDDLを実行しようとした。

今回はオンラインDDLは失敗した。Generated Columnの前にカラム追加するとGenerated Column自体の移動が発生してしまい、オンラインで実行できないようだ。

関数indexで使われる仮想列を避ける

Generated Columnとカラム追加の挙動からすると、やはり関数indexで使用されている仮想列が暗黙でテーブルの末尾に追加されているような挙動になっている。

そのため、Generated Columnをテーブルの適当な位置に追加したうえで、ユニークキー用のインデックスは関数indexとして実装するのではなく、Generated Columnを使用して実装した。

Generated Columnを使用することで、カラム追加時にGenerated Columnより後ろを指定すれば問題なくオンラインDDLが実行できた。