Oracle ACE

MySQL

MySQL 8.0.30+ 引入的 GIPK 特性

下面的内容将详细介绍 MySQL 8.0.32 引入的 GIPK(Generated Invisible Primary Keys,生成不可见主键) 特性。

01. 特性概述

MySQL 8.0.30 引入,8.0.32 进一步完善复制支持。当创建 InnoDB 表时如果未显式定义主键,MySQL 会自动为其生成一个不可见的自增主键列,避免"无主键表"带来的性能和复制问题。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mysql> CREATE TABLE t1(
-> my_row_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT INVISIBLE PRIMARY KEY
-> , c1 INT
-> );
Query OK, 0 rows affected (0.29 sec)

mysql> show create table t1\G
*************************** 1. row ***************************
Table: t1
Create Table: CREATE TABLE `t1` (
`my_row_id` bigint unsigned NOT NULL AUTO_INCREMENT /*!80023 INVISIBLE */,
`c1` 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)

02. 为什么需要 GIPK?

无主键表的问题

在 MySQL 中,没有主键的表会带来多方面问题:

  1. 复制性能。Row-Based Replication(RBR)模式下,无主键表进行 UPDATE/DELETE 时需要全表扫描定位记录,导致严重主从延迟。
  2. 在线 DDL。使用 pt-online-schema-change、gh-ost 等工具进行在线变更时,必须依赖主键进行分片处理。
  3. 集群环境。InnoDB Cluster、Galera、Percona XtraDB Cluster 等集群方案强制要求表必须有主键。
  4. 数据一致性。逻辑备份(mysqldump)和 Binlog 回放时,无主键表难以唯一标识行。

GIPK 的优势

  • 对应用透明:INVISIBLE 属性意味着 SELECT * 不会返回该列,不影响现有业务代码
  • 自动维护:无需人工干预,自动为新表添加主键
  • 性能提升:使 RBR 复制效率提升 50% 以上,支持在线 DDL 工具正常工作

03. 配置与使用

两个核心参数

  • sql_generate_invisible_primary_key

全局、会话级参数。表示是否启用 GIPK 自动生成

  • show_gipk_in_create_table_and_information_schema

会话级参数,默认为 ON,表示是否在 SHOW CREATE TABLE 和 Information Schema 中显示 GIPK 列。

启用方法

1
2
3
4
5
6
7
8
9
-- 全局启用(需 SUPER 权限)
SET GLOBAL sql_generate_invisible_primary_key = ON;

-- 当前会话启用
SET SESSION sql_generate_invisible_primary_key = ON;

-- 或在 my.cnf 中配置
[mysqld]
sql_generate_invisible_primary_key=ON

实际效果示例。

  • 关闭 GIPK 时:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mysql> SET SESSION sql_generate_invisible_primary_key = OFF;
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE t2(id INT, c1 INT);
Query OK, 0 rows affected (0.20 sec)

-- 结构:只有 id 和 c1 两列,无主键
mysql> show create table t2\G
*************************** 1. row ***************************
Table: t2
Create Table: CREATE TABLE `t2` (
`id` int DEFAULT NULL,
`c1` int DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)
  • 开启 GIPK 后:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
mysql> SET sql_generate_invisible_primary_key = ON;
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE t3(id INT, c1 INT);
Query OK, 0 rows affected (0.14 sec)

-- 实际创建的表结构:
mysql> show create table t3\G
*************************** 1. row ***************************
Table: t3
Create Table: CREATE TABLE `t3` (
`my_row_id` bigint unsigned NOT NULL AUTO_INCREMENT /*!80023 INVISIBLE */,
`id` int DEFAULT NULL,
`c1` 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)

查询表现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
-- 隐式查询不包含 GIPK 列,只显示 id, c1
mysql> insert t3 select 1,1;
Query OK, 1 row affected (0.01 sec)
Records: 1 Duplicates: 0 Warnings: 0

mysql> table t3;
+------+------+
| id | c1 |
+------+------+
| 1 | 1 |
+------+------+
1 row in set (0.00 sec)

-- 显式指定才能看到,显示三列
mysql> select my_row_id, id, c1 from t3;
+-----------+------+------+
| my_row_id | id | c1 |
+-----------+------+------+
| 1 | 1 | 1 |
+-----------+------+------+
1 row in set (0.00 sec)

04. 技术细节与限制

1. 触发条件

GIPK 只在以下情况自动生成:

  • 表引擎为 InnoDB
  • 创建时未显式定义主键(PRIMARY KEY)
  • 配置项已开启

注意:如果表有 UNIQUE KEY 但不是 PRIMARY KEY,仍会生成 GIPK 。

2. 命名冲突处理

如果手动创建了名为 my_row_id 的列但未指定主键,会报错:

1
2
mysql> create table t_my_row_id (my_row_id int);
ERROR 4108 (HY000): Failed to generate invisible primary key. Column 'my_row_id' already exists.

解决方案:

  • 将现有 my_row_id 设为主键
  • 或创建其他列作为主键
  • 或临时关闭 GIPK 功能

3. 列操作限制

GIPK 列处于 INVISIBLE 状态时,不能进行以下操作:

  • 重命名列(RENAME COLUMN)
  • 修改列定义
  • 删除列

必须先将其设为 VISIBLE 才能修改 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
-- 先可见化
ALTER TABLE t3 RENAME COLUMN my_row_id TO id;
mysql> ALTER TABLE t3 ALTER COLUMN my_row_id SET VISIBLE;
Query OK, 0 rows affected (0.06 sec)
Records: 0 Duplicates: 0 Warnings: 0

-- 然后可以重命名
mysql> ALTER TABLE t3 RENAME COLUMN my_row_id TO pkid;
Query OK, 0 rows affected (0.04 sec)
Records: 0 Duplicates: 0 Warnings: 0

mysql> show create table t3\G
*************************** 1. row ***************************
Table: t3
Create Table: CREATE TABLE `t3` (
`pkid` bigint unsigned NOT NULL AUTO_INCREMENT,
`id` int DEFAULT NULL,
`c1` int DEFAULT NULL,
PRIMARY KEY (`pkid`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

4. 与显式主键的共存

为已有 GIPK 的表添加显式主键时:

1
2
3
4
5
6
7
8
-- 错误做法:直接添加主键
mysql> alter table t4 add primary key (id);
ERROR 1068 (42000): Multiple primary key defined

-- 正确做法:先删除 GIPK 列,再添加新主键
mysql> alter table t4 drop column my_row_id, add primary key (id);
Query OK, 0 rows affected (0.12 sec)
Records: 0 Duplicates: 0 Warnings: 0

05. 复制场景处理

主从复制行为

关键规则:sql_generate_invisible_primary_key 设置不会随复制传播 。

  • 主库开启 GIPK,从库不会自动为无主键表生成主键
  • 主库关闭 GIPK,从库开启也不会影响主库创建的表

8.0.32+ 的复制增强

从 MySQL 8.0.32 开始,副本端可以强制为复制的无主键表添加 GIPK:

1
2
3
4
-- 在从库执行
CHANGE REPLICA SOURCE TO
REQUIRE_TABLE_PRIMARY_KEY_CHECK = GENERATE
FOR CHANNEL ch1;

副本现在会为通道 ch1 复制创建的表添加一个不可见的主键

注意:GENERATE 模式与 MySQL Group Replication 不兼容 。

06. mysqldump 备份

为防止导出文件包含自动生成的 GIPK 列(这会导致导入时与目标库 GIPK 设置冲突),应使用专用参数:

1
2
3
4
5
# 导出时排除 GIPK 列
mysqldump -uroot -p1 --skip-generated-invisible-primary-key mydb > backup.sql

# 默认情况下,导出时不排除 GIPK 列
mysqldump -uroot -p1 mydb > backup_gipk.sql

对比两次导出的结果集:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[mysql@shawnyan ~]$ diff backup.sql backup_gipk.sql
27,28c27,30
< `id` int DEFAULT NULL
< ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
---
> `my_row_id` bigint unsigned NOT NULL AUTO_INCREMENT /*!80023 INVISIBLE */,
> `id` int DEFAULT NULL,
> PRIMARY KEY (`my_row_id`)
> ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
37c39
< INSERT INTO `t1` VALUES (1);
---
> INSERT INTO `t1` (`my_row_id`, `id`) VALUES (1,1);
50c52
[mysql@shawnyan ~]$

如果不使用该参数,在目标库开启 GIPK 的情况下导入,可能会出现主键冲突或重复列错误。

07. 应用场景与最佳实践

适用场景

  1. 遗留系统改造:老旧应用有大量无主键表,无法修改表结构,通过 GIPK 零侵入解决
  2. 云数据库环境:Azure Database for MySQL 等云厂商默认开启 GIPK,确保所有表都有主键
  3. 集群环境准备:迁移到 InnoDB Cluster 前开启 GIPK,避免主键缺失导致加入集群失败
  4. 大数据同步:使用 Canal、Maxwell 等 Binlog 解析工具时,确保表有主键以提高同步效率

与 sql_require_primary_key 的配合

MySQL 8.0.13 引入的 sql_require_primary_key 可以强制要求创建表必须有主键,与 GIPK 配合使用效果更佳 :

1
2
3
4
5
6
-- 强制要求主键,但允许通过 GIPK 自动满足
SET GLOBAL sql_require_primary_key = ON;
SET GLOBAL sql_generate_invisible_primary_key = ON;

-- 此时创建无主键表不会报错,因为 GIPK 会自动添加主键
CREATE TABLE legacy_table (data VARCHAR(100)); -- 成功,自动有 my_row_id 主键

Have a nice day ~ ☕

🌻 近期内容 ▼

👉 这里有得聊

如果对国产基础软件(操作系统、数据库、中间件)、AI、Vibe Coding、OpenClaw 、Hermes Agent 等感兴趣,可以加群一起聊聊。关注微信公众号:(少安事务所),后台回复[群],即可看到入口。如果这篇文章为你带来了灵感或启发,请帮忙『点赞、推荐、转发』吧,感谢!ღ( ´・ᴗ・` )~