MySQL 8.4 支持为任何没有显式主键的 InnoDB
表生成不可见主键。当 sql_generate_invisible_primary_key
服务器系统变量设置为 ON
时,MySQL 服务器会自动向所有此类表添加一个生成的不可见主键 (GIPK)。此设置对使用除 InnoDB
以外的任何其他存储引擎创建的表没有影响。
默认情况下,sql_generate_invisible_primary_key
的值为 OFF
,这意味着自动添加 GIPK 已禁用。为了说明这如何影响表创建,我们首先创建一个没有主键的两个相同表,唯一的区别是第一个 (表 auto_0
) 是在将 sql_generate_invisible_primary_key
设置为 OFF
的情况下创建的,而第二个 ( auto_1
) 是在将 sql_generate_invisible_primary_key
设置为 ON
的情况下创建的,如下所示
mysql> SELECT @@sql_generate_invisible_primary_key;
+--------------------------------------+
| @@sql_generate_invisible_primary_key |
+--------------------------------------+
| 0 |
+--------------------------------------+
1 row in set (0.00 sec)
mysql> CREATE TABLE auto_0 (c1 VARCHAR(50), c2 INT);
Query OK, 0 rows affected (0.02 sec)
mysql> SET sql_generate_invisible_primary_key=ON;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @@sql_generate_invisible_primary_key;
+--------------------------------------+
| @@sql_generate_invisible_primary_key |
+--------------------------------------+
| 1 |
+--------------------------------------+
1 row in set (0.00 sec)
mysql> CREATE TABLE auto_1 (c1 VARCHAR(50), c2 INT);
Query OK, 0 rows affected (0.04 sec)
比较这些 SHOW CREATE TABLE
语句的输出,以了解表实际创建方式的不同之处
mysql> SHOW CREATE TABLE auto_0\G
*************************** 1. row ***************************
Table: auto_0
Create Table: CREATE TABLE `auto_0` (
`c1` varchar(50) DEFAULT NULL,
`c2` int DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)
mysql> SHOW CREATE TABLE auto_1\G
*************************** 1. row ***************************
Table: auto_1
Create Table: CREATE TABLE `auto_1` (
`my_row_id` bigint unsigned NOT NULL AUTO_INCREMENT /*!80023 INVISIBLE */,
`c1` varchar(50) DEFAULT NULL,
`c2` 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)
由于 auto_1
在用于创建它的 CREATE TABLE
语句中没有指定主键,因此设置 sql_generate_invisible_primary_key = ON
会导致 MySQL 为该表添加不可见列 my_row_id
以及该列上的主键。由于 sql_generate_invisible_primary_key
在创建 auto_0
时为 OFF
,因此未对该表执行此类添加操作。
当服务器向表添加主键时,列名和键名始终为 my_row_id
。因此,当以这种方式启用生成的不可见主键时,您无法创建具有名为 my_row_id
的列的表,除非表创建语句也指定了显式主键。(在这些情况下,您不需要将列名或键名命名为 my_row_id
。)
my_row_id
是一个不可见列,这意味着它不会显示在 SELECT *
或 TABLE
的输出中;必须通过名称显式选择该列。请参见 第 15.1.20.10 节,“不可见列”。
当启用 GIPK 时,生成的不可见主键只能在 VISIBLE
和 INVISIBLE
之间切换。要使 auto_1
上的生成的不可见主键可见,请执行此 ALTER TABLE
语句
mysql> ALTER TABLE auto_1 ALTER COLUMN my_row_id SET VISIBLE;
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> SHOW CREATE TABLE auto_1\G
*************************** 1. row ***************************
Table: auto_1
Create Table: CREATE TABLE `auto_1` (
`my_row_id` bigint unsigned NOT NULL AUTO_INCREMENT,
`c1` varchar(50) DEFAULT NULL,
`c2` int DEFAULT NULL,
PRIMARY KEY (`my_row_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.01 sec)
要使此生成的不可见主键再次不可见,请发出 ALTER TABLE auto_1 ALTER COLUMN my_row_id SET INVISIBLE
。
生成的不可见主键默认情况下始终不可见。
无论何时启用 GIPK,如果您遇到以下两种情况之一,都无法删除生成的不可见主键
表没有主键。
删除了主键,但没有删除主键列。
sql_generate_invisible_primary_key
的影响仅适用于使用 InnoDB
存储引擎的表。您可以使用 ALTER TABLE
语句更改具有生成的不可见主键的表的存储引擎;在这种情况下,主键和列将保留在原处,但表和键不再获得任何特殊处理。
默认情况下,GIPK 会显示在 SHOW CREATE TABLE
、SHOW COLUMNS
和 SHOW INDEX
的输出中,并且在 Information Schema 的 COLUMNS
和 STATISTICS
表中可见。您可以通过将 show_gipk_in_create_table_and_information_schema
系统变量设置为 OFF
,从而在这些情况下隐藏生成的不可见主键。默认情况下,此变量为 ON
,如下所示
mysql> SELECT @@show_gipk_in_create_table_and_information_schema;
+----------------------------------------------------+
| @@show_gipk_in_create_table_and_information_schema |
+----------------------------------------------------+
| 1 |
+----------------------------------------------------+
1 row in set (0.00 sec)
从以下针对 COLUMNS
表的查询可以看出,my_row_id
在 auto_1
的列中可见
mysql> SELECT COLUMN_NAME, ORDINAL_POSITION, DATA_TYPE, COLUMN_KEY
-> FROM INFORMATION_SCHEMA.COLUMNS
-> WHERE TABLE_NAME = "auto_1";
+-------------+------------------+-----------+------------+
| COLUMN_NAME | ORDINAL_POSITION | DATA_TYPE | COLUMN_KEY |
+-------------+------------------+-----------+------------+
| my_row_id | 1 | bigint | PRI |
| c1 | 2 | varchar | |
| c2 | 3 | int | |
+-------------+------------------+-----------+------------+
3 rows in set (0.01 sec)
将 show_gipk_in_create_table_and_information_schema
设置为 OFF
后,my_row_id
将不再在 COLUMNS
表中可见,如下所示
mysql> SET show_gipk_in_create_table_and_information_schema = OFF;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @@show_gipk_in_create_table_and_information_schema;
+----------------------------------------------------+
| @@show_gipk_in_create_table_and_information_schema |
+----------------------------------------------------+
| 0 |
+----------------------------------------------------+
1 row in set (0.00 sec)
mysql> SELECT COLUMN_NAME, ORDINAL_POSITION, DATA_TYPE, COLUMN_KEY
-> FROM INFORMATION_SCHEMA.COLUMNS
-> WHERE TABLE_NAME = "auto_1";
+-------------+------------------+-----------+------------+
| COLUMN_NAME | ORDINAL_POSITION | DATA_TYPE | COLUMN_KEY |
+-------------+------------------+-----------+------------+
| c1 | 2 | varchar | |
| c2 | 3 | int | |
+-------------+------------------+-----------+------------+
2 rows in set (0.00 sec)
sql_generate_invisible_primary_key
的设置不会复制,并且会被复制应用器线程忽略。这意味着该变量在源上的设置不会对副本产生影响。您可以通过使用 REQUIRE_TABLE_PRIMARY_KEY_CHECK = GENERATE
作为 CHANGE REPLICATION SOURCE TO
语句的一部分,使副本为给定复制通道上没有主键的表添加 GIPK。
GIPK 与 CREATE TABLE ... SELECT
的基于行的复制一起使用;在这种情况下,写入二进制日志的信息包含 GIPK 定义,因此可以正确复制。当 sql_generate_invisible_primary_key = ON
时,不支持 CREATE TABLE ... SELECT
的基于语句的复制。
在创建或导入使用 GIPK 的安装的备份时,可以排除生成的不可见主键列和值。用于 mysqldump 的 --skip-generated-invisible-primary-key
选项会导致 GIPK 信息在程序的输出中被排除。