導讀:在使用MySQL建表時,咱們一般會建立一個自增字段(AUTO_INCREMENT),並以此字段做爲主鍵。本篇文章將以問答的形式講述關於自增id的一切。mysql
注: 本文所講的都是基於Innodb
存儲引擎。sql
InnoDB
會選擇主鍵做爲彙集索引、若是沒有顯式定義主鍵,則InnoDB會選擇第一個不包含有NULL值的惟一索引做爲主鍵索引、若是也沒有這樣的惟一索引,則InnoDB會選擇內置6字節長的ROWID做爲隱含的彙集索引(ROWID隨着行記錄的寫入而主鍵遞增,這個ROWID不像ORACLE的ROWID那樣可引用,是隱含的)。綜上而言:當咱們使用自增列做爲主鍵時,存取效率是最高的。緩存
自增id是增加的 不必定連續。測試
咱們先來看下MySQL 對自增值的保存策略:優化
InnoDB 引擎的自增值,實際上是保存在了內存裏,而且到了 MySQL 8.0 版本後,纔有了「自增值持久化」的能力,也就是才實現了「若是發生重啓,表的自增值能夠恢復爲 MySQL 重啓前的值」,具體狀況是:code
在 MySQL 5.7 及以前的版本,自增值保存在內存裏,並無持久化。每次重啓後,第一次打開表的時候,都會去找自增值的最大值 max(id),而後將 max(id)+1 做爲這個表當前的自增值。索引
舉例來講,若是一個表當前數據行裏最大的 id 是 10,AUTO_INCREMENT=11。這時候,咱們刪除 id=10 的行,AUTO_INCREMENT 仍是 11。但若是立刻重啓實例,重啓後這個表的 AUTO_INCREMENT 就會變成 10。事務
也就是說,MySQL 重啓可能會修改一個表的 AUTO_INCREMENT 的值。內存
在 MySQL 8.0 版本,將自增值的變動記錄在了 redo log 中,重啓的時候依靠 redo log 恢復重啓以前的值。rem
形成自增id不連續的狀況可能有:
自增id是整型字段,咱們經常使用int類型來定義增加id,而int類型有上限 即增加id也是有上限的。
下表列舉下 int
與 bigint
字段類型的範圍:
類型 | 大小 | 範圍(有符號) | 範圍(無符號) |
---|---|---|---|
int | 4字節 | (-2147483648,2147483647) | (0,4294967295) |
bigint | 8字節 | (-9223372036854775808,9223372036854775807) | (0,18446744073709551615) |
從上表能夠看出:當自增字段使用int有符號類型時,最大可達2147483647即21億多;使用int無符號類型時,最大可達4294967295即42億多。固然bigint能表示的範圍更大。
下面咱們測試下當自增id達到最大時再次插入數據會怎麼樣:
create table t(id int unsigned auto_increment primary key) auto_increment=4294967295; insert into t values(null); // 成功插入一行 4294967295 show create table t; /* CREATE TABLE `t` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4294967295; */ insert into t values(null); //Duplicate entry '4294967295' for key 'PRIMARY'
從實驗能夠看出,當自增id達到最大時將沒法擴展,第一個 insert 語句插入數據成功後,這個表的AUTO_INCREMENT 沒有改變(仍是 4294967295),就致使了第二個 insert 語句又拿到相同的自增 id 值,再試圖執行插入語句,報主鍵衝突錯誤。
維護方面主要提供如下2點建議: