转:新特性 | MySQL 8.0 隐式主键功能
原文: mp.weixin.qq.com
MySQL 8.0.30 版本发布,这个版本没有带来类似 Hash Join、Instant Add Column、Clone Plugin 这样核弹级的功能,但却带来了一个姜老师期盼 10 年之久的功能,GIPK:Generated Invisible Primary Key,隐式主键功能。
对于 MySQL 熟悉的小伙伴都知道,InnoDB 存储引擎是索引组织表,每张表都有一个 ROWID 列,数据根据 ROWID 排序存放。ROWID 的选择如下:
若定义了主键,则主键列就是 ROWID 列;
若没有主键列,则第一个被定义为 NOT NULL 的唯一索引列即为 ROWID 列;
其他场景,则 InnoDB 存储引擎会自动创建一个 6 字节的隐式主键列;
然而,第 3 种创建 ROWID 的场景会导致一个非常严重的问题!
这个严重的问题是在进行主从同步的时候,由于没有了主键,从机的回放效率极差,大概率会引起主从的延迟,继而影响业务的读取,容灾切换的时效性等各种问题。
主从复制延迟的主要原因是虽然 InnoDB 存储引擎层可以感知自己创建的 ROWID 主键列,但是 MySQL Server 层却无法感知。因为 MySQL 数据库的表结构中并没有这个列。从机的回放是在 Server 上层实现,无法感知 InnoDB 层的隐藏列。
此外,隐式主键也很容易导致在默认的 RR 事务隔离级别下产生全局的行级锁,表现形式就类似全表被锁住了。这样数据库的整体吞吐率亦会受到很大的影响。
虽然每个 MySQL 数据库规范都会写到建表要主动创建一个主键,但在真正的实现生产过程中会遇到一些阻力或问题。因为对于大厂来说,有一套完善的流程管控,而大部分公司没有这样规范的管控机制,导致他们在使用 MySQL 数据库遇到各种各样的问题。
因此,从产品设计角度看,这是谁的问题?MySQL 的错?InnoDB 的错?
以上全错。
MySQL 没有错,InnoDB 也没有错,但是 MySQL + InnoDB 就错了。
要解决这个问题,本质是 MySQL 在 InnoDB 层面会自动创建的隐式主键(若没有显示指定创建 ROWID 列),并且这个隐藏主键不仅对 InnoDB 引擎层可见,对 MySQL Server 层也要可见。
这样,即便用户没有遵循规范,MySQL 也会自动创建一个主键,这样可以方便解决没有主键导致复制同步、加锁等各种问题。
我们知道腾讯云、阿里云等都有自动创建隐藏主键的功能,并且该主键是在 MySQL Server 层创建的,以此解决公有云上用户使用 MySQL 数据库不规范,从而导致的各种问题。
MySQL 8.0.30 版本的 GIPK 功能实现更为优雅,结合列的 Invisible 特性,推出了隐式创建自增主键的功能。
换句话说,只要将参数 sql_generate_invisible_primary_key 设置为 ON,若用户没有显式创建主键,MySQL 自身会创建隐藏的列 my_row_id,并将其定义为主键,该列的定义如下所示:
1 |
|
不得不说,官方 GIPK 的设计真的很优雅,不但解决了 InnoDB 引擎创建隐式主键的问题,甚至是解决了所有存储引擎表的问题。而且满足如果用户希望读取 ROWID 列的话,可以通过隐藏列 my_row_id 或_rowid 标识来访问。如:
对于 GIPK 这个特性来说,唯一需要注意的是:主从服务器间的配置要严格一致。确保参数 sql_generate_invisible_primary_key 在主从的值是一样的。因为,若从机没有设置 GIPK 为 ON,这就意味着复制不会为从机上的表生成隐藏的主键列。
GIPK 特性真的太棒,解决了很多新手使用 MySQL 数据库的问题。但是到这就结束了么?不一定。
换位思考,若我是 MySQL 数据库的首席产品经理,我会如何持续打磨这个功能呢?
首先,我会将参数 sql_generate_invisible_primary_key 的默认值设置为 ON(当前为 OFF),这看起来没有太大的坏处。
当然,如果是低版本到高版本的数据同步,从机会多 1 个隐藏的列,但感觉这并不会导致太大的问题。
另一方面,用 BIGINT 做自增主键虽然可以,但不是最优解的主键推荐,因此可以提供设置隐藏主键的类型,如 BIGINT,UUID 等。这样就可以新增参数:sql_generate_invisible_primary_key_type
到这,做内核研发的小伙伴们是不是跃跃欲试了呢?