単純なカラム追加をオンライン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が実行できた。