##=====================================================================================##

在数据库表设计中会纠结于”自然键”和”代理键”的选择,自然键在实现数据“软删除”时实现比较复杂,部分自然键因为键值过长或多列组合导致不适合作为表主键,而比较常见两种代理键为自增列(auto incremnet)和全局唯一标识列(GUID)。

使用自增列作为主键的优缺点:
1、    主键键值长度短,INT列需要4个字节,BIGINT列需要8个字节;
2、    自增主键顺序递增,在INSERT操作时”顺序”写入表;
3、    由于数据集中插入到表尾部,在高并发情况下容易造成”数据页热点”,影响插入效率;
4、    自增主键只能保证在表内数据唯一,对于分库分表场景,可能因错误操作产生相同的“唯一值”。

使用GUID列的优缺点:
1、    32位GUID字符串需要更多的存储空间来存放(具体存储长度与字符集相关),影响主键和其他索引的查询性能。
2、    GUID可实现全局唯一,能保证在多个表之间的数据唯一性
3、    GUID将数据分散到全表,不会产生热点数据页,但会造成大量随机IO读写

在实际使用过程中,很少场景会使用GUID作为主键,大部分业务按照数据量需求使用INT或BIGINT的自增列作为主键,对于需要多表唯一的场景可以通过程序实现全局唯一的自增ID。

##=====================================================================================##
MySQL在很早版本便支持自增列并在各版本中优化自增列功能,在MySQL 5.1.22版本引入轻量级互斥自增长实现机制,MySQL 5.5版本中引入change buffer特性,在MySQL 8.0版本引入自增列持久化。针对目前京东主要使用MySQL 5.5/5.6/5.7三个主版本,罗列部分使用自增列需要掌握的知识点:

知识点1:自增列数据类型选择问题
自增列除常见的TINYINT/SMALLINT/INT/BIGINT等整数数据类型外,还可以使用FLOAT等浮点数数据类型,但强烈建议不使用非整数数据类型作为自增列。
选取数据类型时:
1、    按照所需要范围值进行最小化选取,如果只需要0-20的范围值,则选择可以存放-128到127数值的TINYINT。
2、    当所需自增范围值不确定时,建议选择足够使用的数据类型,先保证数据安全再考虑操作性能,相同数据量下,使用BIGINT并不会比使用INT带来太多性能影响。京东订单号在前期设计时使用INT数据类型,当INT无法满足需求时,商城花费大量资源进行INT到BIGINT的升级改造,同时影响诸多关联系统。

##=====================================================================================##
知识点2:自增列跳号问题
1、无论MySQL还是其他关系型数据库,为提高自增列的生成效率,都将生成自增值的操作设计为非事务性操作,表现为当事务回滚时,事务中生成的自增值不会被回滚。
2、当对自增表进行批量插入时(INSERT … SELECT …),即使在单一会话下,MySQL仍不能保证两次获取到的自增ID值连续,批量插入数据量越大,产生的自增ID跳号范围越大。

自增跳号对普通业务没有太多影响,但对于像发票这类要求号码连续的业务,不能通过自增列来实现。

##=====================================================================================##
知识点3:自增列持久化问题
在MySQL 5.5/5.6/5.7三个版本中,MySQL并不会将自增列分配的自增值信息固化到磁盘,当MySQL重启后,会根据自增列上当前最大值和参数auto_increment_offset来确定下一次的自增值,为快速获取自增列上最大值,MySQL要求自增列必须建有索引。如果一张自增表的数据在重启实例前被清空,实例重启后该表数据会从”1”开始自增(假设表的自增初始值定义为1)。
 
在一次亚一数据库升级过程中,某张业务表”恰好”因为业务逻辑将表中所有数据删除,重启后该表自增值从1开始生成,当该表数据流转到其他表出现数据冲突,发现问题后,我们紧急手动设置该表自增值,避免事故进一步恶化,并再后期类似操作时,重点关注此类自增表。
 
建议1:如果业务会对自增表数据进行硬删除,在服务器重启前应重点关注该自增表使用的自增值,可以通过information_schema.tables中的auto_increment列来获取。
 
PS1:在MySQL 8.0中引入自增列持久化特性,可以避免上述问题。

##=====================================================================================##
知识点4:自增列初始值问题
在运维过程中,会遇到研发同事问为什么新创建的表不是从1开始自增,该问题可以从以下两个角度排查:
1、    建表语句,在使用SHOW CREATE TABLE或MySQLDump等命令导出表结构时,会包含该表当前使用的自增值,如:
 

2、    全局参数auto_increment_increment和auto_increment_offset,这两全局参数可以作用实例下所有自增表,主要应用在分库分表的场景。

##=====================================================================================##
知识点5:修改数据列为自增数据列
当数据类型为数值类型且表中数据唯一时,可以将该数据列转换为自增列,修改操作会保持列中现有数据,不会重新生成新数据。

##=====================================================================================##
知识点6:修改普通表为自增表
在MySQL中允许使用ALTER TABLE方式为普通表新增一个自增列,但由于ALTER操作为DDL语句,在主从复制时会将该DDL语句传递给从库执行,MySQL并不能保证相同记录在主从服务器上获得相同的自增ID,会导致主从数据差异。
模拟测试:

主库上创建表:
CREATE TABLE TB1001
(
C1 INT
); 会话1开启事务并执行:
START TRANSACTION;
INSERT INTO TB1001(C1) SELECT 1; 会话2执行:
INSERT INTO TB1001(C1) SELECT 2; 会话1提交事务。 然后将表修改为自增表:
ALTER TABLE TB1001 ADD ID INT PRIMARY KEY AUTO_INCREMENT;

主库数据为:
 
从库数据为:
 

原因分析:
在主库上,C1=2的数据晚于C1=1的数据被插入,但由于C1=2的数据所在事务被先提交,因此C1=2的记录先于C1=1的记录在从库上执行,因此两条记录在主库和从库上的插入顺序不同,在生成自增ID时获得到自增ID不同,最终导致数据差异。

建议:在将普通表修改为自增表时,如果表中存在数据,请勿使用ALTER TABLE的方式修改,建议新建自增临时表,然后将数据导入到该表中,再兑换表名。

##=====================================================================================##

MySQL--自增列学习的更多相关文章

  1. (转)mysql自增列导致主键重复问题分析

    mysql自增列导致主键重复问题分析...  原文:http://www.cnblogs.com/cchust/p/3914935.html 前几天开发童鞋反馈一个利用load data infile ...

  2. mysql自增列导致主键重复问题分析。。。

    前几天开发童鞋反馈一个利用load data infile命令导入数据主键冲突的问题,分析后确定这个问题可能是mysql的一个bug,这里提出来给大家分享下.以免以后有童鞋遇到类似问题百思不得其解,难 ...

  3. MySQL自增列(AUTO_INCREMENT)相关知识点总结

      MySQL的自增列(AUTO_INCREMENT)和其它数据库的自增列对比,有很多特性和不同点(甚至不同存储引擎.不同版本也有一些不同的特性),让人感觉有点稍微复杂.下面我们从一些测试开始,来认识 ...

  4. MySQL自增列锁模式 innodb_autoinc_lock_mode不同参数下性能测试

    对于innodb_autoinc_lock_mode 各种参数的值的含义,网上也有各种详解,看完觉得意犹未尽,这里不做阐述,只动手测试,看看性能上,到底有没有理论上所说的差别.对于自增列的锁定,据说是 ...

  5. Mysql 自增列 主键

    Mysql中假如有 ID Int auto_increment, CID varchar(36). 通常情况下都是 ID设置为主键. 假如要设置CID为主键.自增列ID必需是唯一索引. create ...

  6. 重置Mysql自增列的开始序号

    ALTER TABLE  TableName AUTO_INCREMENT = 5; 代表重新从5开始(包括5)

  7. 怎么重置mysql的自增列AUTO_INCREMENT初时值

    重置 MySQL 自增列 AUTO_INCREMENT 初时值 注意, 使用以下任意方法都会将现有数据删除. 方法一: delete from tb1; ALTER TABLE tbl AUTO_IN ...

  8. MySQL AutoIncrement--自增锁模式

    自增锁模式 在MYSQL 5.1.22版本前,自增列使用AUTO_INC Locking方式来实现,即采用一种特殊的表锁机制来保证并发插入下自增操作依然是串行操作,为提高插入效率,该锁会在插入语句完成 ...

  9. [MySQL FAQ]系列 — 为什么InnoDB表要建议用自增列做主键

    我们先了解下InnoDB引擎表的一些关键特征: InnoDB引擎表是基于B+树的索引组织表(IOT): 每个表都需要有一个聚集索引(clustered index): 所有的行记录都存储在B+树的叶子 ...

随机推荐

  1. dsPIC30F 细节点问题不定期更新ing

    知识点1 TRISD: I/O 引脚 方向控制 寄存器 (1--input, 0--Output)LATD:  I/O 引脚 输出锁存器PORTD: 是双向I/O 端口 备注:LATD = 0x000 ...

  2. 在centos7 部署bbr

    How to Deploy Google BBR on CentOS 7 Published on: Thu, Jan 5, 2017 at 6:34 pm EST CentOS Linux Guid ...

  3. Linux服务器上监控网络带宽的18个常用命令 zz

    Linux服务器上监控网络带宽的18个常用命令 本文介绍了一些可以用来监控网络使用情况的Linux命令行工具.这些工具可以监控通过网络接口传输的数据,并测量目前哪些数据所传输的速度.入站流量和出站流量 ...

  4. Security.ssl-pinning

    SSL Pinning 1. What's SSL Pinning? "SSL Pinning is making sure the client checks the server’s c ...

  5. python基础 (装饰器,内置函数)

    https://docs.python.org/zh-cn/3.7/library/functions.html 1.闭包回顾 在学习装饰器之前,可以先复习一下什么是闭包? 在嵌套函数内部的函数可以使 ...

  6. pyadb关于python操作adb的资料

    3.最后adb命令由于是android的原生操作命令,支持实现的功能非常多.这里举几个pyapp里实现的功能例子:获取,修改手机当前使用的输入法(adb shell ime list),获取当前手机界 ...

  7. 用grunt对css代码进行压缩

    1.先安装Node.js环境 Grunt和 Grunt 插件是通过 npm 安装并管理的,npm是 Node.js 的包管理器.Node.js的下载链接 安装完后进行验证 2.安装grunt及插件 通 ...

  8. GUI学习之五——QAbstractButton类学习笔记

    今天总结一下AbstractButton类的学习笔记. 一.描述 AbstractButton是对各种按键的抽象类他的继承关系是这样的 首先,QAbstractButton继承了QWidget类的各种 ...

  9. SpringBoot放置在static下面的静态页面无法访问

    最近写项目本来写的好好的,突然static的静态页面访问不了了. 于是我各种上网查资料,看大佬的解决方案,还是没有解决. 直到发现了这篇文章 https://blog.csdn.net/cmqwan/ ...

  10. playframework 一步一步来 之 日志 (三)

    在paly中自定义配置logback,也很简单,只需在conf folder下添一个application-logger.xml或者logger.xml就行了.(出处:"If you cre ...