问题现象:

Mysql插入一条数据时,未指定自增键的值却报错:自增键重复,无法插入!

执行SQL

INSERT INTO `test`.`test_sort`(`id`, `name`, `age`, `birthday`) VALUES
(10027, '测试', 23, '2020-01-07 12:23:11')

报错:

INSERT INTO `test`.`test_sort`(`id`, `name`, `age`, `birthday`) VALUES
(10027, '测试', 23, '2020-01-07 12:23:11')
> 1062 - Duplicate entry '38' for key 'sort'
> 时间: 0.001s

表的创建语句:

CREATE TABLE `test_sort`  (
`id` int(11) NOT NULL COMMENT '主键',
`name` varchar(24) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '姓名',
`age` tinyint(3) UNSIGNED NULL DEFAULT NULL COMMENT '年龄',
`birthday` datetime(0) NULL DEFAULT NULL COMMENT '生日',
`sort` int(11) NOT NULL AUTO_INCREMENT COMMENT '序号',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `sort`(`sort`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 39 CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Dynamic;

这里可以发现,sort字段在表中是自增键,通过唯一索引 sort 来实现,而我在插入新行的时候没有指定 sort 字段的值,那么它理论上会采用当前自增 B-Tree 上最大数字 + 1,这里却提示他冲突了。

问题还原

表里面原来的数据如下:

INSERT INTO `test_sort` VALUES (10001, '张三', 23, '2020-01-07 12:23:11', 1);
INSERT INTO `test_sort` VALUES (10002, '王五', 23, '2020-01-07 12:23:11', 9);
INSERT INTO `test_sort` VALUES (10003, '赵六', 23, '2020-01-07 12:23:11', 10);
INSERT INTO `test_sort` VALUES (10004, '钱七', 23, '2020-01-07 12:23:11', 11);
INSERT INTO `test_sort` VALUES (10005, '刘八', 23, '2020-01-07 12:23:11', 12);
INSERT INTO `test_sort` VALUES (10006, '冯九', 23, '2020-01-07 12:23:11', 13);
INSERT INTO `test_sort` VALUES (10007, '李四', 23, '2020-01-07 12:23:11', 44);
INSERT INTO `test_sort` VALUES (10008, '李四1', 23, '2020-01-07 12:23:11', 36);
INSERT INTO `test_sort` VALUES (10009, '王五1', 23, '2020-01-07 12:23:11', 38);
INSERT INTO `test_sort` VALUES (10010, '赵六1', 23, '2020-01-07 12:23:11', 40);
INSERT INTO `test_sort` VALUES (10011, '钱七1', 23, '2020-01-07 12:23:11', 41);
INSERT INTO `test_sort` VALUES (10012, '刘八1', 23, '2020-01-07 12:23:11', 46);
INSERT INTO `test_sort` VALUES (10013, '冯九1', 23, '2020-01-07 12:23:11', 47);
INSERT INTO `test_sort` VALUES (10014, '李四1', 23, '2020-01-07 12:23:11', 48);
INSERT INTO `test_sort` VALUES (10015, '王五1', 23, '2020-01-07 12:23:11', 21);
INSERT INTO `test_sort` VALUES (10016, '赵六1', 23, '2020-01-07 12:23:11', 22);
INSERT INTO `test_sort` VALUES (10017, '钱七1', 23, '2020-01-07 12:23:11', 23);
INSERT INTO `test_sort` VALUES (10018, '刘八1', 23, '2020-01-07 12:23:11', 24);
INSERT INTO `test_sort` VALUES (10019, '冯九1', 23, '2020-01-07 12:23:11', 25);
INSERT INTO `test_sort` VALUES (10021, '测试', 23, '2020-01-07 12:23:11', 28);
INSERT INTO `test_sort` VALUES (10022, '测试', 23, '2020-01-07 12:23:11', 30);
INSERT INTO `test_sort` VALUES (10023, '测试', 23, '2020-01-07 12:23:11', 32);
INSERT INTO `test_sort` VALUES (10024, '测试', 23, '2020-01-07 12:23:11', 33);
INSERT INTO `test_sort` VALUES (10025, '测试', 23, '2020-01-07 12:23:11', 34);
INSERT INTO `test_sort` VALUES (10026, '测试', 23, '2020-01-07 12:23:11', 37);

这里在数据插入时,我通过 Navicat 手动修改了表中 sort 字段的值,改成一个比原来最大值。此时再重新添加数据,当自增键的值增长到该值时,就会报该错误。

解决方法

删除原来用于自增的唯一索引 sort,然后重新创建该索引。记得删除后点保存,之后添加索引,保存

删除时出现该提示是因为自增长必须依赖索引存在,索引应该先去掉该键的自增长功能。在重新添加索引后打开该功能

受《高性能Mysql》的启发

这本书里面有句:通过一个不做任何操作的 ALTER 操作来重建表。而我们的删除-重新添加操作和他有异曲同工之妙。

启发

这次问题给我带来的启发如下,也请同行们参考

  1. 不到万不得已不要手动去修改数据库的唯一索引字段
  2. 如果修改了,修改之后通过删除 + 重新添加索引的方式避免线上服务出错
  3. 书中自有黄金屋,如果不是之前读过自增键、索引相关的知识,遇到此事便不能及时解决,可能会造成无法挽回的损失,书到用时方恨少...

Mysql唯一索引线上故障记录的更多相关文章

  1. MySQL慢日志线上问题分析及功能优化

    本文来源于数据库内核专栏. MySQL慢日志(slow log)是MySQL DBA及其他开发.运维人员需经常关注的一类信息.使用慢日志可找出执行时间较长或未走索引等SQL语句,为进行系统调优提供依据 ...

  2. MySQL 分区表 partition线上修改分区字段,后续进一步学习partition (1)

    公司线上在用partition,有一个表的分区字段错了,需要重建,结果发现没有办法像修改主键字段或者修改索引字段那样直接一条sql搞定.而是需要建临时表,有down time,所以去仔细看了文档,研究 ...

  3. mysql 唯一索引与null.md

    mysql 的唯一索引要求所有参与的列都不能够为 null 值,如果唯一索引中的任何一个元素含有 null 值,则唯一约束将不起作用. 示例代码 create table tb ( a int, b ...

  4. mysql 唯一索引UNIQUE使用方法详解

    创建唯一索引的目的不是为了提高访问速度,而只是为了避免数据出现重复.唯一索引可以有多个但索引列的值必须唯一,索引列的值允许有空值.如果能确定某个数据列将只包含彼此各不相同的值,在为这个数据列创建索引的 ...

  5. MySQL死锁系列-线上死锁问题排查思路

    前言 MySQL 死锁异常是我们经常会遇到的线上异常类别,一旦线上业务日间复杂,各种业务操作之间往往会产生锁冲突,有些会导致死锁异常.这种死锁异常一般要在特定时间特定数据和特定业务操作才会复现,并且分 ...

  6. 【MySQL】实现线上千万数据表添加字段操作以及缓存刷新

    需求背景: 由于业务需求,需要在线上用户表添加渠道字段,用于区分不同渠道注册的用户,目前该表有20+个字段,8个索引 线上用户数据大概1500W左右,需要不停机增加数据库字段,同时需要刷新Redis缓 ...

  7. MySQL数据库如何线上修改表结构

    一.MDL元数据锁 在修改表结构之前,先来看下可能存在的问题. 1.什么是MDL锁 MySQL有一个把锁,叫做MDL元数据锁,当对表修改的时候,会自动给表加上这把锁,也就是不需要自己显式使用. 当对表 ...

  8. 关于Mysql唯一索引的操作方法(添加删除)

    首先我们查看一下News数据表的索引信息      使用命令 show index from ‘数据表名称’; 目前数据表中仅有一个主键索引 继续,我们给news表添加两个唯一索引(两种方法) 方法一 ...

  9. MySQL数据库索引(上)

    上一篇回顾: 1.数据页由七部分组成,包括File Header(描述页的信息).Page Header(描述数据的信息).Infimum + Supremum(页中的虚拟数据最大值和最小值).Use ...

随机推荐

  1. EF的多线程与分库架构设计实现(2)

    距离上次讲解EF6分库架构(https://www.cnblogs.com/gbat/p/6374607.html)实现已经过去2年了..上次发出来后,一直到现在依然有很多人陆陆续续的加我好友,问我要 ...

  2. 2019-8-31-dotnet-通过-WMI-拿到显卡信息

    title author date CreateTime categories dotnet 通过 WMI 拿到显卡信息 lindexi 2019-08-31 16:55:58 +0800 2019- ...

  3. @bzoj - 4380@ [POI2015] Myjnie

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 有 n 家洗车店从左往右排成一排,每家店都有一个正整数价格 p[ ...

  4. shell去掉最后一个字符

    实测过第一种写法,可正常删除 sed 's/.$//' awk '{sub(/.$/,"")}1' awk '{printf $0"\b \n"}' ufile ...

  5. day8_python网络编程(实验版本)

    1.简单的套接字通信 1.1.服务端 import socket # 买手机 phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 插 ...

  6. day5_python之subprocess模块

    subprocess作用:用来执行系统命令它会开启一个子进程,通过子进程去执行一些命令 读取正确的命令执行结果,如果没有指定把结果输出到哪里,默认打印到屏幕上 #subprocess.Popen(r' ...

  7. rowStyle设置Bootstrap Table行样式

    日常开发中我们通常会用到隔行变色来美化表格,也会根据每行的数据显示特定的背景颜色,如果库存低于100的行显示红色背景 CSS样式 <style> .bg-blue { background ...

  8. lrj 9.2.3

    <<); // 记忆化搜索 min[] = ; int dp(int i) { ) return maxv[i]; maxv[i] = -INF; ; j <= n; j++) if ...

  9. lua在C/C++中使用table生成对应键及值

    int nTop = lua_gettop(L); // 栈内初始数,假设当前为0 lua_newtable(L); // push table lua_pushstring(L,"Line ...

  10. iptables单个规则实例

    iptables -F? # -F 是清除的意思,作用就是把 FILTRE TABLE 的所有链的规则都清空 iptables -A INPUT -s 172.20.20.1/32 -m state ...