以前就有過這樣的疑問,最近在學習MySQL這一塊,突然又想到了這個問題,就自己動手實驗了一下,請看過程。
先創建一張簡單的表,插入一條數據
create table test(id int unsigned auto_increment primary key);
insert into test values(null);
查看一下表情況,
show create table test
我們發現 AUTO_INCREMENT 已經自動變成2,這離用完還有很遠,我們可以算下最大當前聲明的自增ID最大是多少,由於這裏定義的是 intunsigned
,所以最大可以達到2^32 - 1 = 4294967295
所以我們改一下,在創建表的時候,直接聲明AUTO_INCREMENT的初始值。
create table t1(id int unsigned auto_increment primary key) auto_increment = 4294967295;
再查看一下,可以發現,AUTO_INCREMENT已經變成4294967295了
再插入一條數據 insert into t1 values(null);
再次插入數據的時候,拿到的數據還是4294967295,因爲這條數據在數據庫中已經存在,所以就會報主鍵衝突的錯誤。4294967295,這個數字已經可以應付大部分的場景了,如果你的服務會經常性的插入和刪除數據的話,還是存在用完的風險,建議採用bigint unsigned,這個數字就大了。
不過,還存在另一種情況,如果在創建表沒有顯示申明主鍵,會怎麼辦?
如果是這種情況,
首先:如果表沒有顯示聲明主鍵,會先查看錶中有沒有唯一鍵值列(即某一列被unique修飾),如果有,則不會創建row_id,而是默認以這種列爲主鍵,如果沒有才會創建row_id。
InnoDB會自動幫你創建一個不可見的、長度爲6字節的row_id,而且InnoDB 維護了一個全局的 dictsys.row_id,所以未定義主鍵的表都共享該row_id,每次插入一條數據,都把全局row_id當成主鍵id,然後全局row_id加1
該全局row_id在代碼實現上使用的是bigint unsigned類型,但實際上只給row_id留了6字節,這種設計就會存在一個問題:如果全局row_id一直漲,一直漲,直到2的48冪次-1時,這個時候再+1,row_id的低48位都爲0,結果在插入新一行數據時,拿到的row_id就爲0,存在主鍵衝突的可能性。
所以,爲了避免這種隱患,每個表都需要定一個主鍵。