MySQL 自增列使用上的一些 “坑”

文章目录

    • 前言
    • 1. 自增列空洞
      • 1.1 手动指定
      • 2.2 分配未使用
    • 2. 自增列监控
      • 2.1 sys 库监控
      • 2.2 通用查询
    • 3. 一些 BUG
      • 3.1 重启失效
      • 3.2 冲突问题

前言

MySQL 的规范中,一般都会建议表要有主键,常使用自增列作为主键字段,这和 MySQL 属于聚簇索引表有关,顺序增长的主键比较合适。最近有研发咨询,为什么有张表的自增主键变的非常大?而且偶尔还出现 Duplicate entry '4' for key 'PRIMARY' 的异常,这篇文章将介绍此类问题。

1. 自增列空洞

1.1 手动指定

自增列的空洞一般指的就是自增列不是连续增长,中间出现一些数值上的断层,这种情况常发生在手动指定自增列的值,请看下面的 case:

-- 创建一张测试表,id 为自增主键
create table t1(id bigint auto_increment primary key,c1 varchar(10) not null,c2 varchar(10) not null
);

插入测试数据:

insert into t1(c1, c2) VALUES ('a', 'b'),('a', 'b'),('a', 'b'),('a', 'b'),('a', 'b');
idc1c2
1ab
2ab
3ab
4ab
5ab

此时再插入手动 ID 插入数据:

insert into t1 value (10, 'a', 'b');

再查询 t1 表的自增值:

select TABLE_NAME, AUTO_INCREMENT from information_schema.TABLES where TABLE_NAME = 't1';
TABLE_NAMEAUTO_INCREMENT
t111

查询表中的数据:

idc1c2
1ab
2ab
3ab
4ab
5ab
10ab

此时可以看到表中的数据只有 6 行,但是自增值已经变为 6,浪费了中间四个值,如果为主键字段为 INT 类型,浪费过多会导致字段溢出,插入数据时就会报错,所以规范里也提到使用 bigint 类型作为表的主键。
请添加图片描述

2.2 分配未使用

自增列有一个特点,就是一旦分配后,就无法被 rollback 相当于被 “浪费”,请看下方 case:

-- 创建一张测试表,id 为自增主键
create table t1(id bigint auto_increment primary key,c1 varchar(10) not null,c2 varchar(10) not null
);

开启事务,插入一条数据,然后回滚:

-- 开启事务
begin;
-- 插入一条记录
insert into t1(c1, c2) value('a', 'b');
-- 回滚
rollback;
-- 再次插入数据
insert into t1(c1, c2) value('a', 'b');
idc1c2
2ab

可以看到自增列是从 2 开始分配的,相当于第一个事务拿到了自增值,但是没有实际使用。

除了 Rollback 会产生分配未使用的情况外,还有 REPLACEINSERT…ON DUPLICATE KEY UPDATE 在特定情况下也会出现分配未使用的情况:

-- 创建测试表,注意 c1 字段有唯一索引
create table t1
(id bigint auto_increment,c1 varchar(10) not null,c2 varchar(10) not null,PRIMARY KEY (`id`),UNIQUE KEY uqk_c1(c1)
);

插入测试数据:

insert into t1(c1, c2) VALUES ('a', 'b'),('b', 'b');

使用 REPLACE 语句:

-- 如果有 c1 = a 将 c2 修改为 w
replace into t1(c1, c2) value ('a', 'w');
-- 上面已经修改了值,下面执行后数据没有实际变化
replace into t1(c1, c2) value ('a', 'w');
replace into t1(c1, c2) value ('a', 'w');
replace into t1(c1, c2) value ('a', 'w');
replace into t1(c1, c2) value ('a', 'w');
replace into t1(c1, c2) value ('a', 'w');

此时表中只有两条记录:

idc1c2
2bb
8aw

再看该表的 AUTO_INCREMENT 值,已经增长到 9 相当于产生了空洞:

select TABLE_NAME, AUTO_INCREMENT from information_schema.TABLES where TABLE_NAME = 't1';
TABLE_NAMEAUTO_INCREMENT
t19

除此之外,还有 DUPLICATE KEY UPDATE 语法也会有此类情况。这两个操作会获取自增列的值,但是经常不会触发 insert,而是 update。

insert into t1(c1, c2) value ('a', 'b') on duplicate key update c2 = 'vvvv';

2. 自增列监控

2.1 sys 库监控

为了防止自增列的值 “用光”,导致业务报错。可以使用下方 SQL 监控自增列:

select * from sys.schema_auto_increment_columns;

2.2 通用查询

如果你的数据库不支持使用这条 SQL(版本问题,或者有些云厂商没有开放 sys 库)可以使用下方 SQL:

SELECT table_schema,table_name,column_name,c.COLUMN_TYPE,AUTO_INCREMENT,POW(2, CASE data_typeWHEN 'tinyint' THEN 7WHEN 'smallint' THEN 15WHEN 'mediumint' THEN 23WHEN 'int' THEN 31WHEN 'bigint' THEN 63END + (column_type LIKE '% unsigned')) - 1 AS max_int
FROM information_schema.tables tJOIN information_schema.columns c USING (table_schema, table_name)
WHERE c.extra = 'auto_increment'and c.COLUMN_KEY = 'PRI'AND t.TABLE_SCHEMA NOT IN ('information_schema', 'mysql', 'sys', 'performance_schema')AND t.auto_increment IS NOT NULL;

3. 一些 BUG

3.1 重启失效

MySQL 5.7 版本 auto_increment 是存储在内存中的,这就导致每次重启 MySQL 都会重新计算该值,计算逻辑是取该字段的 MAX VALUE 请看下方 case:

-- 创建一张测试表,id 为自增主键
create table t1(id bigint auto_increment primary key,c1 varchar(10) not null,c2 varchar(10) not null
);

插入 8 行记录:

insert into t1(c1, c2) value ('a', 'b'),('a', 'b'),('a', 'b'),('a', 'b'),('a', 'b'),('a', 'b'),('a', 'b'),('a', 'b');

此时 AUTO_INCREMENT 的值为 9,下一条写入会被分配自增 ID 为 9:

select TABLE_NAME, AUTO_INCREMENT from information_schema.TABLES where TABLE_NAME = 't1';
TABLE_NAMEAUTO_INCREMENT
t19

然后删除后 4 条记录:

delete from t1 where id > 4;

重启数据库:

>$ service mysqld restart
Shutting down MySQL.... SUCCESS! 
Starting MySQL... SUCCESS! 

查询 t1 表的自增 ID:

select TABLE_NAME, AUTO_INCREMENT from information_schema.TABLES where TABLE_NAME = 't1';
TABLE_NAMEAUTO_INCREMENT
t15

可以看到 MySQL 在重启之后自增列的值被重置了。这个现象被称之为 BUG 主要是在现在的互联网业务中,支撑业务数据的不仅仅只有 MySQL,还可能会有 Redis,RabbitMQ 等缓存和消息队列或者是单独的 MySQL 日志归档库,自增列可能会被用来作为关联各个存储之间的“逻辑外键”,当 MySQL 重启之后,新写入的数据可能会用到已经被删除的值,导致数据库中的数据和外部系统之间的数据出现错误的关联。另外一种问题场景就是 MySQL 自身各个表之间有外键关系,但是没有建立外键约束,也会遇到类似的问题。

该 BUG 已在 MySQL 8.0 版本修复。

3.2 冲突问题

当自增列被修改过时,可能会出现 Duplicate entry '4' for key 'PRIMARY' 的异常,详细看下方 case:

-- 创建一张测试表,id 为自增主键
create table t1(id bigint auto_increment primary key,c1 varchar(10) not null,c2 varchar(10) not null
);

插入测试数据:

insert into t1(c1, c2) VALUES ('a', 'b'),('a', 'b'),('a', 'b'),('a', 'b'),('a', 'b');

修改自增列的值:

update t1 set id = 6 where id = 1;-- 表中数据:
+----+----+----+
| id | c1 | c2 |
+----+----+----+
|  2 | a  | b  |
|  3 | a  | b  |
|  4 | a  | b  |
|  5 | a  | b  |
|  6 | a  | b  |
+----+----+----+

再尝试获取自增值插入:

insert into t1(c1, c2) VALUES ('a', 'b');

ERROR 1062 (23000): Duplicate entry ‘6’ for key ‘PRIMARY’

这个 case 报错的原因是 UPDATE 修改了自增列的值,但是 UPDATE 不会触发自增值的分配,却占用了一个未来要被分配的自增值,当该值需要被分配出来的时候,由于被 UPDATE 修改的行占用了,导致 SQL 报错,所以主键(自增列)尽量不要去修改。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/351768.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

SQL——事务

🎈 什么是事务 💧 概念 事务是用于保证数据的一致性,它由一组相关的DML(增、删、改)语句,该组的DML语句要么全部成功,要么全部失败。使用事务可以确保数据库的一致性和完整性,避免数据出现异常…

蓝屏代码0x00000074

前台电脑系统是win7,用着用着突然蓝屏(代码0x00000074),网上都说是内存条或者选择最近一次正确的配置,但是我发现进bios都识别不到固态硬盘,以为硬盘坏了就换了一个就可以了,但是用了一星期不到…

0x0000007B是什么意思?解决方案

0x0000007b电脑蓝屏通常情况是硬盘的存储控制器驱动加载错误导致故障。对于这种情况就要有相应解决措施,下面来看看具体解决方法。 导致驱动加载错误的情况可能有以下三种情况: 1.无法自动识别硬盘控制器: 使用非正版的个别操作系统光盘&…

问题解决:应用程序错误0xc00007b

1. 问题出现 在安装软件lightroom的时候,出现了应用程序错误0xc00007b,程序无法打开,尝试了好些办法,最终是安装一个插件解决了问题。 2. 问题解决 安装aio-runtimes软件,里面包含一些基本软件所需要的库&#xff0c…

应用程序无法正常启动(0xc000007b)的解决办法

应用程序无法正常启动(0xc000007b)的解决办法。 有时候我们启动程序会发现以下错误,如图所示: 解决方法1: (1)根据下图指示,以管理员身份打开CMD (2)输入…

如何解决错误0×80071AC3

前几天我在机房敲百例的时候,敲完了想把文件夹移动到我的U盘里去,结果出现了这种情况 上面说运行chkdsk并重试,我运行了一下,没什么反应,我就想既然不能移动文件夹了,那就试试能不能移动文档好了&#xff0…

应用程序无法正常启动0xc000007b win7

1. 一开始报错 下载dll放到同级目录后报下一个错误。 (这里注意:搜索的时候就发现大多数dll都是 vc_runtime 140 没有d,d表示debug。同事指点:使用vscode生成解决方案时要用release模式,不是debug模式,这也…

蓝屏stop:0x000000007B (oxf78aa524,Oxcooooo34

神舟飞天超级本安装键盘后提示错误,开机后,反复按f2,进入bios,高级SATA选项,发现我的默认是AHCI的模式我设置为IDE,按f4保存退出后正常了.

电脑运行应用程序出现0xc000007b的解决方法

在我们使用Windows操作系统的计算机时,双击运行程序,它无法运行而且还会出现一个这样的对话框(如下图),总之程序就是运行不了,让人很头疼,这次教大家如何解决这个问题。 出现这样的问题,是电脑里面的几个文…

无法正常启动0xc000007b的解决方法

最近在我的电脑上用VS10-x64 release编译好了一个软件,用了VC,openCV以及其他的库,在我们已经装了VS10的电脑上运行都没有问题,但是在一台全新的电脑上安装上我发布的软件就出问题了。客户要求我们不能装VS10软件,于是我们装了VC1…

Spring-data-jpa最全的查询语法总结,直入超神

🤵‍♂️ 个人主页:香菜的个人主页 ✍🏻作者简介:csdn 认证博客专家,游戏开发领域优质创作者,华为云享专家,2021年度华为云年度十佳博主 🐋 希望大家多多支持,我们一起进步&#xff…

0x0000007b电脑蓝屏的解决方法

AHCI是高级主机控制接口,可以发挥SATA硬盘潜在的加速功能,尤其是固态硬盘,更加需要使用AHCI硬盘模式,开启ahci一般在安装系统之前进入BIOS进行设置,但是不同主板BIOS设置界面不尽相同,很多人都不懂bios怎么…

蓝屏0x0000007b要怎么办?有什么简单的处理方法?

遇到蓝屏0x0000007b要怎么办?相信很多人都遇到过吧?这种蓝屏其实是很让人烦恼的,会导致系统直接无法使用,今天小编就来给大家详细的说说。 一.电脑蓝屏0x0000007b怎么办 1.首先点击开机键将电脑关闭,然后重启电脑开机按下F10进入bios。 2.选…

出现蓝屏代码0x0000007b的原因及解决办法

出现蓝屏代码0x0000007b的原因通常是硬盘的存储控制器驱动加载错误,我们可以通过对BIOS界面进行修复来解决这个问题。下面小编将详细介绍解决蓝屏代码0x0000007b的方法,一起来看看吧 导致驱动加载错误的情况有以下三种: 一、无法自动识别硬盘…

有效解决应用程序无法正常启动(0xc000007b)的错误

尝试了各种办法,最后就这个方法非常实用!一下子就解决了问题!大家快来用! 博主遇到的问题是SPSS、Origin和某些绘图软件集体失灵,都显示无法正常启动应用程序 知道肯定是缺少了一些东西,于是开始自己手动…

0xc000007b应用程序无法正常启动解决方案(亲测有效)

这种问题的出现,大多数都是不小心删掉了c的静态库的东西,解决方案有很多,但是都有点复杂,我这里提供两种方法,可以解决大部分用户的难题。 在这里奉劝小伙伴们一句,不要手欠去动系统软件哈,就是…

软件提示无法正常启动0xc000007b的解决方法

#软件提示无法正常启动0xc000007b的解决方法 0xc000007b问题是由于我们缺少电脑.dll运行库问题所导致的,所以可以 下载DirectX修复工具进行修复: 可修复DirectX运行库VC个版本运行库msvcp.dll等各类dll缺失问题 当初博主遇到这个问题的时候&#xff…

应用程序无法正常启动(0xc000007b)解决

注:本文对0xc000007b的问题本质进行了说明,可以说对网上杂七杂八的声音做了一个统一。 问题情景: vs2013 写的一个64位的exe程序,release后带着来自系统目录C:\Windows\SysWOW64\msvcr120.dll 到一个没有runtime的win7环境去运行&…

应用程序无法正常启动0xc00007b的解决(二)

【背景】 基于Visual Studio环境开发的程序换一个运行环境时常常出现这样的情况:先提示“无法启动此程序,因为计算机丢失**.dll。尝试重新安装该程序以解决此问题”,很容易想到的办法就是从原来的环境中搜索相应的**.dll,然后放到…

应用程序无法正常启动,提示错误代码0xc000007b怎么办?

许多用户在访问《FIFA》、《孤岛惊魂》、《使命召唤》等游戏或其他应用程序时,收到了0xc000007b错误,提示“应用程序无法正常启动(0xc000007b)”。 导致错误代码0xc000007b的原因有很多,小编列出的是相对常见的原因: 1、当你尝试启…