MariaDB10.3から導入されたsystem versioned table(正確にはTemporal Data Tablesというらしい)ですが、一見するととても便利な機能ですが、ちょっと注意が必要です。
(ひとつめ)
CREATE時にSQLモードの影響を受ける。
SQLモードに「NO_ZERO_DATE」(もしくはTRADITIONAL)が入っていて、「0000-00-00」などの無効な日時を弾く定義を行っているとCREATEできない。(当然ALTER時も影響を受けます)
MariaDB [test]> select @@sql_mode; +------------------------------------------------------------------------------------------------------------------------------------------------------+ | @@sql_mode | +------------------------------------------------------------------------------------------------------------------------------------------------------+ | STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION | +------------------------------------------------------------------------------------------------------------------------------------------------------+
MariaDB [test]> create table t_sv ( -> user_id int not null, -> name varchar(32) not null, -> primary key (user_id) -> ) with system versioning; ERROR 1067 (42000): Invalid default value for 'row_start'
とまあ、こんな感じです。
当方の環境では、「NO_ZERO_DATE」と「TRADITIONAL」を落とすことで、CREATE可能になりました。
(ふたつめ)
row_endというカラム(レコードが切り替えられた日時であり、上のDDLだと勝手にそのような名前で作成される)は実はPRIMARY KEYである。
show create table の結果だと、
MariaDB [test]> show create table t_sv; +-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | t_sv | CREATE TABLEt_sv
(user_id
int(11) NOT NULL,name
varchar(32) NOT NULL, PRIMARY KEY (user_id
) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 WITH SYSTEM VERSIONING | +-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
となるのですが、show index の結果をみると、
MariaDB [test]> show index from t_sv; +-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | t_sv | 0 | PRIMARY | 1 | user_id | A | 0 | NULL | NULL | | BTREE | | | | t_sv | 0 | PRIMARY | 2 | row_end | A | 0 | NULL | NULL | | BTREE | | | +-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
というように、user_idとrow_endでPRIMARY KEY となっている。
show create table 上は出てこないのに、不思議。
ちまみに、information_schema.statistics のテーブルにも出てきているので、アプリケーション上で自動的にPRIMARY KEY の判定を行って、何かをしている場合は注意が必要です。
しかし、実は例外もあって、以下のようにそもそもPRIMARY KEY がないテーブルだとrow_endにPRIMARY KEY が設定されない。
CREATE TABLE t (x INT) WITH SYSTEM VERSIONING PARTITION BY SYSTEM_TIME INTERVAL 1 WEEK ( PARTITION p0 HISTORY, PARTITION p1 HISTORY, PARTITION p2 HISTORY, PARTITION pcur CURRENT );
これまた超絶不思議。おそらくはclustered indexに自動的に決定されることが起因しているのかもしれない。
試しにxをPRIMARY KEY に変更したら以下のようなエラーがでた。
MariaDB [test]> alter table t add primary key (x); ERROR 4119 (HY000): Not allowed for system-versionedtest
.t
. Change @@system_versioning_alter_history to proceed with ALTER.
どうやら変更できないみたい。
(みっつめ)
公式にも書いてありますが、mysqldumpを使った時に、現在のレコードのみが出力されます。
つまり、mysqldumpではsystem versioned table のバックアップはできません。
そのほか、
- 同じデータであっても隠しカラムの値のため、CHECKSUM の値が同じにならない
- データを変更してなくても、ON UPDATEが走る(row_startとかが変わるから)
といった特徴もあります。
安易に使うと、意外なところでハマりそうな気がしますが、社内システムなど限られた環境で扱う分は、威力を発揮しそうな感じがします。
system versioned table はトランザクションIDの履歴対応やら、10.4でアプリケーションタイムをサポートするなど、今後も改良が加えられていくと思いますので、個人的には期待してます。
以上