はじめに
MySQL 8.0.30 から、Generated Invisible Primary Keys(GIPKs) という機能が追加されています。
この機能を有効にすることで、主キーの存在しないテーブルを作成した際に、自動で Invisible Columns の主キーを追加することができます。
MySQL 8.0.32 ではこの機能の拡張として、レプリケーションのレプリカで主キーのないテーブルを複製する場合にも対応できるようになりました。
Replication: It is now possible to cause a replica to add a generated invisible primary key to any InnoDB table that otherwise, as replicated, has no primary key.
引用 : Changes in MySQL 8.0.32 (2023-01-17, General Availability)
今回はこの新機能について、挙動や仕様について確認してみたいと思います。
Generated Invisible Primary Keys(GIPKs) について
まず GIPKs とは、明示的に主キーを指定せずに作成したテーブルに対して、非表示のカラムを追加する機能です。
具体的には、以下のような仕様となっています。
-
sql_generate_invisible_primary_key システム変数で動作を制御する
デフォルトでは無効になっている sql_generate_invisible_primary_key を有効にすることで、GIPKs の機能が適用されるようになります。なお、動的かつグローバル・セッション単位で指定することが可能です。1234567mysql> SHOW GLOBAL VARIABLES LIKE 'sql_generate_invisible_primary_key';+------------------------------------+-------+| Variable_name | Value |+------------------------------------+-------+| sql_generate_invisible_primary_key | OFF |+------------------------------------+-------+1 row in set (0.03 sec)また、この値はレプリケーション時に伝播しないため、伝播させるには後述する CHANGE REPLICATION SOURCE TO 文のオプションとして指定する必要があります。
-
作成される主キー名は my_row_id
GIPKs は主キーのないテーブルを作成した際に、カラムの先頭に非表示の my_row_id 列を作成します。
非表示カラム(Invisible Columns)として作成されるため、ユーザー側は特に意識することなく普段通りテーブルを使用することが可能です。123456789101112131415mysql> SET SESSION sql_generate_invisible_primary_key = ON;Query OK, 0 rows affected (0.00 sec)mysql> CREATE TABLE test.t1(id int);Query OK, 0 rows affected (0.03 sec)mysql> SHOW CREATE TABLE test.t1\G*************************** 1. row ***************************Table: t1Create Table: CREATE TABLE 't1' ('my_row_id' bigint unsigned NOT NULL AUTO_INCREMENT /*!80023 INVISIBLE */,'id' int DEFAULT NULL,PRIMARY KEY ('my_row_id')) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci1 row in set (0.00 sec)また、GIPKs が有効になっていて主キーのないテーブルを作成する際には、my_row_id という名前のカラムは作成できないので注意してください。なお、主キーのあるテーブルでは my_row_id カラムを追加することが可能です。
12345mysql> CREATE TABLE test.t2(my_row_id int);ERROR 4108 (HY000): Failed to generate invisible primary key. Column 'my_row_id' already exists.mysql> CREATE TABLE test.t2(id int PRIMARY KEY,my_row_id int);Query OK, 0 rows affected (0.01 sec)
この他、GIPKs が有効になっている場合、MySQL 8.0.32 時点では、新たに主キーを追加しないで主キーを削除する操作がエラーとなります。
1 2 |
mysql> ALTER TABLE test.t1 DROP PRIMARY KEY; ERROR 1235 (42000): This version of MySQL doesn't yet support 'existing primary key drop without adding a new primary key. In @@sql_generate_invisible_primary_key=ON mode table should have a primary key. Please add a new primary key to be able to drop existing primary key.' |
ちなみにこの挙動は、テーブル作成時に主キーがない場合はエラーにする sql_require_primary_keyと被っているようです。似たシステム変数なので、今後統合されると嬉しいですね。
Generated Invisible Primary Keys(GIPKs) を利用したレプリケーションの仕様について
前述している通り、sql_generate_invisible_primary_key の値はレプリケーション時に伝播しないため、レプリケーションのレプリカで GIPKs を利用するためには CHANGE REPLICATION SOURCE TO 文で REQUIRE_TABLE_PRIMARY_KEY_CHECK = GENERATE を指定する必要があります。
したがって、レプリカサーバーで sql_generate_invisible_primary_key を有効にしていても、REQUIRE_TABLE_PRIMARY_KEY_CHECK = GENERATE を指定していなければレプリケーション SQL スレッドにおいて GIPKs は有効にならないので注意してください。
なお、グループレプリケーションにおいて REQUIRE_TABLE_PRIMARY_KEY_CHECK = GENERATE はサポートされていないため、ON/OFF あるいはデフォルト値の STREAM を指定する必要があります。
既存のレプリケーションに追加をおこなう場合は、以下のように一度レプリケーションを停止してから設定を追記すると、以降の DDL で GIPKs が有効になります。また設定については、performance_schema.replication_applier_configuration テーブルから確認可能です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
mysql> STOP REPLICA; Query OK, 0 rows affected (0.02 sec) mysql> CHANGE REPLICATION SOURCE TO REQUIRE_TABLE_PRIMARY_KEY_CHECK=GENERATE; Query OK, 0 rows affected (0.02 sec) mysql> START REPLICA; Query OK, 0 rows affected (0.01 sec) mysql> SELECT * FROM performance_schema.replication_applier_configuration\G *************************** 1. row *************************** CHANNEL_NAME: DESIRED_DELAY: 0 PRIVILEGE_CHECKS_USER: NULL REQUIRE_ROW_FORMAT: NO REQUIRE_TABLE_PRIMARY_KEY_CHECK: GENERATE ASSIGN_GTIDS_TO_ANONYMOUS_TRANSACTIONS_TYPE: OFF ASSIGN_GTIDS_TO_ANONYMOUS_TRANSACTIONS_VALUE: NULL 1 row in set (0.00 sec) |
ここで、レプリケーションにおける GIPKs の挙動については以下のように、GIPKs をサポートしている(MySQL 8.0.30 以降の)ソースと MySQL 8.0.32 以降のレプリカにおける GIPKs に基づく相違はサポートされ、MySQL 8.0.29 以前のソースの場合はレプリケーションエラーが発生する可能性があるとの記載があります。
A divergence based on the presence of a generated invisible primary key solely on a source or replica table is supported by MySQL Replication as long as the source supports GIPKs (MySQL 8.0.30 and later) and the replica uses MySQL version 8.0.32 or later. If you use GIPKs on a replica and replicate from a source using a MySQL 8.0.29 or earlier, you should be aware that in this case such divergences in schema are not supported and may result in replication errors.
引用: 13.4.2.3 CHANGE REPLICATION SOURCE TO Statement – REQUIRE_TABLE_PRIMARY_KEY_CHECK
しかし、たとえば以下のように MySQL 8.0.32 の GIPKs が無効のソースサーバーで主キーの追加をおこなうと、GIPKs を有効にしているレプリカサーバーではレプリケーションエラーが発生してしまいます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
[ソースサーバー(MySQL8.0.32)] mysql> CREATE TABLE test.t3(id int); Query OK, 0 rows affected (0.02 sec) mysql> ALTER TABLE test.t3 ADD PRIMARY KEY(id); Query OK, 0 rows affected (0.01 sec) Records: 0 Duplicates: 0 Warnings: 0 [レプリカサーバー(MySQL8.0.32)] mysql> SHOW CREATE TABLE test.t3\G *************************** 1. row *************************** Table: t3 Create Table: CREATE TABLE 't1' ( 'my_row_id' bigint unsigned NOT NULL AUTO_INCREMENT /*!80023 INVISIBLE */, 'id' int DEFAULT NULL, PRIMARY KEY ('my_row_id') ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci 1 row in set (0.00 sec) mysql> SHOW REPLICA STATUS\G (...) Replica_IO_Running: Yes Replica_SQL_Running: No (...) mysql> SELECT * FROM performance_schema.replication_applier_status_by_worker\G (...) LAST_ERROR_NUMBER: 1068 LAST_ERROR_MESSAGE: Worker 1 failed executing transaction 'ANONYMOUS' at master log binlog.000003, end_log_pos 4146; Error 'Multiple primary key defined' on query. Default database: ''. Query: 'ALTER TABLE test.t1 ADD PRIMARY KEY(id)' LAST_ERROR_TIMESTAMP: 2023-02-21 18:29:17.275586 LAST_APPLIED_TRANSACTION: ANONYMOUS (...) |
その他、ソースサーバーで my_row_id という名前のカラムを追加してもエラーになりますし、主キーが存在するテーブルから主キーを削除してもレプリカサーバーではエラーが発生してしまいます。
そのため、実質的にはソースあるいはレプリカサーバーでのみ GIPKs を有効にすることで、意図的にデータ不整合を発生させる可能性があることになるため、慎重に運用していく必要がありそうです。
まとめ
ここまで、GIPKs およびレプリケーションの挙動について確認してきました。
主キーのない環境からのレプリケーションでも自動で主キーが追加されるため、行ベースレプリケーション を使用している際に主キーがないテーブルへの UPDATE や DELETE が遅くなる問題が懸念される環境において、ソースサーバー側で操作をおこなわなずに対策ができるのは便利かと思います。
※既存のテーブルには有効でないため、あらかじめ GIPKs を有効にしてから論理バックアップを流すなどのひと手間が必要になる点にはご注意ください
ただし、実際はソースとレプリカ間でデータの不整合が発生しており、今回のように特定の DDL を実行したりフェイルオーバーを実施すると、思わぬ障害につながる可能性もあるため、実環境で使用する際には、問題がないかどうかを十分注意して利用する必要がありそうです。