标签: 公众号文章mysql
咱们在建表的时候为某个索引列(注意:必须是索引列)添加AUTO_INCREMENT
属性,就像这样:sql
CREATE TABLE t (
c1 TINYINT AUTO_INCREMENT,
c2 TINYINT,
KEY idx_c1 (c1)
) ENGINE=InnoDB;
复制代码
表t
中包含一个索引列c1
,该列被添加了AUTO_INCREMENT
属性。咱们先向该表中插入一条记录:bash
mysql> INSERT INTO t(c1, c2) VALUES(126, 1);
Query OK, 1 row affected (0.02 sec)
复制代码
以后咱们再也不在INSERT
语句中显式地插入c1
列的值,它的默认值就将是从当前插入的最大的那个值以后自增,好比这样:markdown
mysql> INSERT INTO t(c2) VALUES(1);
Query OK, 1 row affected (0.01 sec)
复制代码
咱们看一下此时表t
中的数据:函数
mysql> SELECT * FROM t; +-----+------+ | c1 | c2 | +-----+------+ | 126 | 1 | | 127 | 1 | +-----+------+ 2 rows in set (0.02 sec) 复制代码
由于c1
列是TINYINT
类型的,使用1个字节存储数据,它能存储最大的值就是127
,若是当该列的值到达127
以后,咱们继续向表中插入数据,自增列c1
的值将会变成什么呢?oop
mysql> INSERT INTO t(c2) VALUES(1);
Query OK, 1 row affected (0.01 sec)
复制代码
插入成功以后咱们再看一下表中的数据:spa
mysql> SELECT * FROM t; +-----+------+ | c1 | c2 | +-----+------+ | 126 | 1 | | 127 | 1 | | 127 | 1 | +-----+------+ 3 rows in set (0.01 sec) 复制代码
很显然,自增列c1
的值将再也不继续增加,而是取的TINYINT
所能存储的最大值。设计
这里须要注意的是,在当前举的例子中,咱们只是在自增列c1
上边创建了一个普通的二级索引idx_c1
,因此键值重复也没啥问题。不过咱们通常将AUTO_INCREMENT
属性应用在表的主键上,此时若是自增列值达到了主键对应数据类型所能存储的最大值时,就会报错(由于主键值重复),你们必定注意!code
在咱们使用InnoDB
存储引擎来建表时,若是咱们本身没有显式地建立主键时,存储引擎会默认找一个具备NOT NULL
属性的惟一二级索引列来充当主键,若是咱们在建表语句中也没有写具备NOT NULL
属性的惟一二级索引列,那很抱歉,存储引擎默认会为咱们添加一个称之为row_id
的主键列。orm
这个row_id
列默认是6个字节大小,值得注意的是,设计InnoDB
的大叔并非为每个用户未显式建立主键的表的row_id
列都单独维护一个计数器,而是全部的表都共享一个全局的计数器。比方说咱们没有对表t1
和t2
显式建立主键,存储引擎为它们都建立了一个row_id
列,若是咱们向表t1
中插入了一条记录,那么就从全局计数器里分配一个值作该表row_id
列的值,而后将全局计数器加1;接着咱们再向表t2
中插入一条记录,那么就再从全局计数器里分配一个值作该表row_id
列的值,而后将全局计数器加1。
有不少同窗有疑惑,若是这个全局计数器的值超过了6个字节所能表示的最大值时,会发生什么,全局计数器从0从新开始技术,一切从头再来么?
哈哈😄,并不会这样。虽然row_id
由6个字节组成,可是设计InnoDB
的大叔倒是使用8个字节存储全局计数器的值,他们将这8个字节分两次写入row_id
,第一次写入右边四个字节到row_id
的右边4个字节,接着将左边四个字节再写入row_id
的左边的2个字节,就像这样:
在将全局计数器左边四个字节再写入row_id
的左边的2个字节 时采用以下函数:
UNIV_INLINE void mach_write_to_2( /*============*/ byte* b, /*!< in: pointer to two bytes where to store 也就是row_id值前2个字节所在的内存地址*/ ulint n) /*!< in: ulint integer to be stored 也就是全局计数器的左4个字节值*/ { ut_ad(b); ut_ad((n | 0xFFFFUL) <= 0xFFFFUL); b[0] = (byte)(n >> 8); b[1] = (byte)(n); } 复制代码
能够看到代码中有这样一行:
ut_ad((n | 0xFFFFUL) <= 0xFFFFUL);
复制代码
这是一个断言函数,这行代码的意思就是全局计数器的左边4个字节值n
必须不大于2个字节所能存储的最大值,不然的话断言就失败了,而后MySQL就挂掉了,就挂掉了,就挂掉了~
也就是说若是row_id
用完了以后MySQL就会挂掉,那种程序直接退出的挂掉~ 不过6个字节已经足够大了,你们能够算算若是想让MySQL挂掉须要插入多少条记录呢?
写文章挺累的,有时候你以为阅读挺流畅的,那实际上是背后无数次修改的结果。若是你以为不错请帮忙转发一下,万分感谢~ 这里是个人公众号「咱们都是小青蛙」,里边有更多技术干货,时不时扯一下犊子,欢迎关注: