MySQL8新特性:自增主键的持久化详解

前言

自增主键没有持久化是个比较早的bug,这点从其在官方bug网站的id号也可看出(https://bugs.mysql.com/bug.php?id=199)。由Peter Zaitsev(现Percona CEO)于2003年提出。历史悠久且臭名昭著。

首先,直观的重现下。

mysql> create table t1(id int auto_increment primary key);
Query OK, 0 rows affected (0.01 sec)

mysql> insert into t1 values(null),(null),(null);
Query OK, 3 rows affected (0.01 sec)
Records: 3 Duplicates: 0 Warnings: 0

mysql> select * from t1;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
+----+
rows in set (0.00 sec)

mysql> delete from t1 where id=3;
Query OK, 1 row affected (0.36 sec)

mysql> insert into t1 values(null);
Query OK, 1 row affected (0.35 sec)

mysql> select * from t1;
+----+
| id |
+----+
| 1 |
| 2 |
| 4 |
+----+
rows in set (0.01 sec)

虽然id为3的记录删除了,但再次插入null值时,并没有重用被删除的3,而是分配了4。

删除id为4的记录,重启数据库,重新插入一个null值。

mysql> delete from t1 where id=4;
# service mysqld restart
mysql> insert into t1 values(null);
Query OK, 1 row affected (0.00 sec)

mysql> select * from t1;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
+----+
rows in set (0.00 sec)

可以看到,新插入的null值分配的是3,按照重启前的操作逻辑,此处应该分配5啊。

这就是自增主键没有持久化的bug。究其原因,在于自增主键的分配,是由InnoDB数据字典内部一个计数器来决定的,而该计数器只在内存中维护,并不会持久化到磁盘中。当数据库重启时,该计数器会通过下面这种方式初始化。

SELECT MAX(ai_col) FROM table_name FOR UPDATE; 

MySQL 8.0的解决思路

将自增主键的计数器持久化到redo log中。每次计数器发生改变,都会将其写入到redo log中。如果数据库发生重启,InnoDB会根据redo log中的计数器信息来初始化其内存值。为了尽量减小对系统性能的影响,计数器写入到redo log中,并不会马上刷新。具体可参考:https://dev.mysql.com/worklog/task/?id=6204

因自增主键没有持久化而出现问题的常见场景:

1. 业务将自增主键作为业务主键,同时,业务上又要求主键不能重复。

2. 数据会被归档。在归档的过程中有可能会产生主键冲突。

所以,强烈建议不要使用自增主键作为业务主键。刨除这两个场景,其实,自增主键没有持久化的问题并不是很大,远没有想象中的”臭名昭著“。

最后,给出一个归档场景下的解决方案,

创建一个存储过程,根据table2(归档表)自增主键的最大值来初始化table1(在线表)。这个存储过程可放到init_file参数指定的文件中,该文件中的SQL会在数据库启动时执行。

DELIMITER ;;
CREATE PROCEDURE `auto_increment_fromtable2`(IN table1 VARCHAR(255), IN table2 VARCHAR(255))
BEGIN
set @qry = concat('SELECT @max1 := (`id` + 1) FROM `',table1,'` ORDER BY `id` DESC LIMIT 1;');
 prepare stmt from @qry;
execute stmt;
deallocate prepare stmt;
 set @qry = concat('SELECT @max2 := (`id` + 1) FROM `',table2,'` ORDER BY `id` DESC LIMIT 1;');
 prepare stmt from @qry;
execute stmt;
deallocate prepare stmt;
IF @max1 < @max2 THEN
 set @qry = concat('alter table `',table1,'` auto_increment=',@max2);prepare stmt from @qry;execute stmt;deallocate prepare stmt;
SELECT 'updated' as `status`;
else
SELECT 'no update needed' as `status`;
END IF;
END ;;
DELIMITER ;

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • MySQL 8 新特性之Invisible Indexes

    背景 索引是把双刃剑,在提升查询速度的同时会减慢DML的操作.毕竟,索引的维护需要一定的成本.所以,对于索引,要加上该加的,删除无用的.前者是加法,后者是减法.但在实际工作中,大家似乎更热衷于前者,而很少进行后者.究其原因,在于后者,难.难的不是操作本身,而是如何确认一个索引是无用的. 如何确认无用索引 在不可见索引出现之前,大家可以通过sys.schema_unused_indexes来确定无用索引.在MySQL 5.6中,即使没有sys库,也可通过该视图的基表来进行查询. mysql> sh

  • MySQL 8.0的关系数据库新特性详解

    前言 MySQL 8.0 当前的最新版本是 8.0.4 rc,估计正式版本出来也快了.本文介绍几个 8.0 在关系数据库方面的主要新特性. 你可能已经知道 MySQL 从版本 5.7 开始提供了 NoSQL 存储的功能,在 8.0 中这部分功能也得到了一些改进,但鉴于这个在实际当中用得极少,本人也是没用过,所以本文不会介绍这方面的东西,而是关注其关系数据库方面. 1.隐藏索引 隐藏索引的特性对于性能调试非常有用.在 8.0 中,索引可以被"隐藏"和"显示".当一个索

  • Mysql 8 新特性 window functions 的作用

    MySQL 8.0的新特性包括: 对Unicode 9.0的开箱即用的完整支持 支持窗口函数和递归SQL语法,这在以往是不可能或者很难才能编写这样的查询语句 对原生JSON数据和文档存储功能的增强支持 MySQL 8.0的发布,跳过了多个版本号(从5.5开始),由于6.0修改和7.0是用来保留做MySQL的集群版本,因此采用了8.0的版本号. 1. 问题 Mysql 8.0.2 中新增加了一个主要功能 - 窗口函数 window function 这个功能具体是解决什么问题?下面先看一个SQL查

  • MySQL8新特性:持久化全局变量的修改方法

    前言 在8之前的版本中,对于全局变量的修改,其只会影响其内存值,而不会持久化到配置文件中.数据库重启,又会恢复成修改前的值.从8开始,可通过SET PERSIST命令将全局变量的修改持久化到配置文件中. 试举一例 mysql> show variables like '%max_connections%'; +------------------------+-------+ | Variable_name | Value | +------------------------+-------+

  • MySQL8新特性:降序索引详解

    前言 MySQL 8.0终于支持降序索引了.其实,从语法上,MySQL 4就支持了,但正如官方文档所言,"they are parsed but ignored",实际创建的还是升序索引. 无图无真相,同一个建表语句,看看MySQL 5.7和8.0的区别. create table slowtech.t1(c1 int,c2 int,index idx_c1_c2(c1,c2 desc)); MySQL 5.7 mysql> show create table slowtech.

  • MySQL8新特性:自增主键的持久化详解

    前言 自增主键没有持久化是个比较早的bug,这点从其在官方bug网站的id号也可看出(https://bugs.mysql.com/bug.php?id=199).由Peter Zaitsev(现Percona CEO)于2003年提出.历史悠久且臭名昭著. 首先,直观的重现下. mysql> create table t1(id int auto_increment primary key); Query OK, 0 rows affected (0.01 sec) mysql> inser

  • MySQL8新特性之降序索引底层实现详解

    什么是降序索引 大家可能对索引比较熟悉,而对降序索引比较陌生,事实上降序索引是索引的子集. 我们通常使用下面的语句来创建一个索引: create index idx_t1_bcd on t1(b,c,d); 上面sql的意思是在t1表中,针对b,c,d三个字段创建一个联合索引. 但是大家不知道的是,上面这个sql实际上和下面的这个sql是等价的: create index idx_t1_bcd on t1(b asc,c asc,d asc); asc表示的是升序,使用这种语法创建出来的索引叫做

  • MySQL8自增主键变化图文详解

    目录 一.简述 二.MySQL自增主键 为什么MySQL8新特性会修改自增主键属性? 如何解决自增主键冲突问题? 三.自增主键测试 1.MySQL5.7自增主键 2.MySQL8自增主键 总结 一.简述 MySQL版本从5直接大跃进到8,相信MySQL8一定会有很多令人意想不到的改进,如果不想只会CRUD可以看看. 比如系统表引擎的变化-全部换成事务型的InnoDB. MySQL5.7系统部引擎 MySQL8系统引擎 上图可以看到,MySQL5.7的系统表引擎有MEMORY.InnnoDB和My

  • Java8新特性:Lambda表达式之方法引用详解

    1.方法引用简述 方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法.方法引用提供了一种引用而不执行方法的方式,它需要由兼容的函数式接口构成的目标类型上下文.计算时,方法引用会创建函数式接口的一个实例. 当Lambda表达式中只是执行一个方法调用时,不用Lambda表达式,直接通过方法引用的形式可读性更高一些.方法引用是一种更简洁易懂的Lambda表达式. Lambda表达式全文详情地址:http://blog.csdn.net/sun_promise/article/details/

  • Java8新特性之重复注解与类型注解详解

    目录 Java8新特性重复注解与类型注解 一.JDK5中的注解 1.注解(@) 2.作用 3.如何理解注解? 4.关于注解 5.注解分为三个阶段 6.注解的属性类型 7.为注解增加属性 二.Java8中的注解 1.类型注解 2.重复注解 三.Java8对注解的增强 Java8新特性重复注解与类型注解 在Java8之前,在某个类或者方法,字段或者参数上标注注解时,同一个注解只能标注一次.但是在Java8中,新增了重复注解和类型注解,也就是说,从Java8开始,支持在某个类或者方法,字段或者参数上标

  • mybatisplus 复合主键(多主键) CRUD示例详解

    目录 mybatisplus复合主键CRUD 需求描述 mybatisplus-plus mybatisplus 复合主键CRUD 需求描述 最近接到个挺有意思的需求,做用户观看学习视频时长的一个数据埋点 储存用户观看视频时长.记录的接口的调用肯定会特别频繁,因为每间隔指定时间每个用户都会调用,如果在这个接口里直接操作数据库将会给我们的数据库带来一定的压力,在我的代码中是不允许的,而我是这样完成这个需求的: 首先将用户观看视频的时长.记录存储到阿里云的日志库里,随后以定时器从阿里云的日志库中拉取

  • ES6新特性一: let和const命令详解

    本文实例讲述了ES6新特性中的let和const命令.分享给大家供大家参考,具体如下: 1. let 命令 ① 在js中是没有块级作用域的,var 声明的变量作用域是整个函数体,而let可以起到这一作用 { let a = 1; var b = 2; } console.log(b); // 2 console.log(a); // a is not defind ② 而let可以起到这一作用啊在js中变量和函数的声明会提升到当前作用域最顶部执行.这样就会出现问题. var a = []; //

  • ES6新特性八:async函数用法实例详解

    本文实例讲述了ES6新特性之async函数用法.分享给大家供大家参考,具体如下: 1. async 函数是什么? node.js 版本7及之后版本才支持该函数. 可以简单的理解为他是Generator 函数的语法糖,即Generator 函数调用next() 返回的结果. ① Generator 函数需要next() 或执行器进行执行,而async 函数只需和普通函数一样执行. ② async和await,比起星号和yield,语义更清楚了.async表示函数里有异步操作,await表示紧跟在后

  • Laravel5.5新特性之友好报错以及展示详解

    前言 期待已久的laravel5.5 很快将为大家呈现,本文将给大家详细介绍关于Laravel5.5新特性之友好报错及展示的相关内容,分享出来供大家参考学习,话不多说了,来一起看看详细的介绍: Laravel5.5 获取源代码 如今Laravel5.5官网并未正式发布,预计就是这几天的事情了! 开发者是可以通过以下命令获取laravel5.5源码的: laravel new laravel55demo --dev 通过命令安装完成后可以使用 php artisan --version 查看版本

  • C++11新特性之随机数库(Random Number Library)详解

    目录 从前的随机数 随机数库(Random Number Library) 随机数引擎 随机数分布类 生成平均分布的整数 生成平均分布的实数 生成正态分布的实数 生成概率可控的布尔值 补充:真正的随机数 总结 从前的随机数 C++11之前,无论是C,还是C++都使用相同方式的来生成随机数,代码大致如下: 由于rand()产生的是伪随机数,所以需要为rand函数提供种子.种子不同产生的随机数序列也不同.通常的做法是调用srand(time(0)),由于time返回的是系统时间,每秒都会不同,所以产

随机推荐