共計 2360 個字符,預計需要花費 6 分鐘才能閱讀完成。
這篇文章主要為大家展示了“Mysql 自增 id 的示例分析”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓丸趣 TV 小編帶領大家一起研究并學習一下“Mysql 自增 id 的示例分析”這篇文章吧。
導讀:
在使用 MySQL 建表時,我們通常會創建一個自增字段 (AUTO_INCREMENT),并以此字段作為主鍵。本篇文章將以問答的形式講述關于自增 id 的一切。
注:本文所講的都是基于 Innodb 存儲引擎。
1.MySQL 為什么建議將自增列 id 設為主鍵?
如果我們定義了主鍵 (PRIMARY KEY),那么 InnoDB 會選擇主鍵作為聚集索引、如果沒有顯式定義主鍵,則 InnoDB 會選擇第一個不包含有 NULL 值的唯一索引作為主鍵索引、如果也沒有這樣的唯一索引,則 InnoDB 會選擇內置 6 字節長的 ROWID 作為隱含的聚集索引 (ROWID 隨著行記錄的寫入而主鍵遞增,這個 ROWID 不像 ORACLE 的 ROWID 那樣可引用,是隱含的)。
數據記錄本身被存于主索引(一顆 B +Tree)的葉子節點上。這就要求同一個葉子節點內(大小為一個內存頁或磁盤頁)的各條數據記錄按主鍵順序存放,因此每當有一條新的記錄插入時,MySQL 會根據其主鍵將其插入適當的節點和位置,如果頁面達到裝載因子(InnoDB 默認為 15/16),則開辟一個新的頁(節點)
如果表使用自增主鍵,那么每次插入新的記錄,記錄就會順序添加到當前索引節點的后續位置,當一頁寫滿,就會自動開辟一個新的頁
如果使用非自增主鍵(如果身份證號或學號等),由于每次插入主鍵的值近似于隨機,因此每次新紀錄都要被插到現有索引頁得中間某個位置,此時 MySQL 不得不為了將新記錄插到合適位置而移動數據,甚至目標頁面可能已經被回寫到磁盤上而從緩存中清掉,此時又要從磁盤上讀回來,這增加了很多開銷,同時頻繁的移動、分頁操作造成了大量的碎片,得到了不夠緊湊的索引結構,后續不得不通過 OPTIMIZE TABLE 來重建表并優化填充頁面。
綜上而言:當我們使用自增列作為主鍵時,存取效率是最高的。
2. 自增列 id 一定是連續的嗎?
自增 id 是增長的 不一定連續。
我們先來看下 MySQL 對自增值的保存策略:
InnoDB 引擎的自增值,其實是保存在了內存里,并且到了 MySQL 8.0 版本后,才有了“自增值持久化”的能力,也就是才實現了“如果發生重啟,表的自增值可以恢復為 MySQL 重啟前的值”,具體情況是:
在 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 恢復重啟之前的值。
造成自增 id 不連續的情況可能有:
1. 唯一鍵沖突
2. 事務回滾
3.insert … select 語句批量申請自增 id
3. 自增 id 有上限嗎?
自增 id 是整型字段,我們常用 int 類型來定義增長 id,而 int 類型有上限 即增長 id 也是有上限的。
下表列舉下 int 與 bigint 字段類型的范圍:
類型大小范圍(有符號)范圍(無符號)int4 字節 (-2147483648,2147483647)(0,4294967295)bigint8 字節 (-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 值,再試圖執行插入語句,報主鍵沖突錯誤。
4. 關于自增列 我們該怎么維護?
維護方面主要提供以下 2 點建議:
1. 字段類型選擇方面:推薦使用 int 無符號類型,若可預測該表數據量將非常大 可改用 bigint 無符號類型。
2. 多關注大表的自增值,防止發生主鍵溢出情況。
以上是“Mysql 自增 id 的示例分析”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注丸趣 TV 行業資訊頻道!