MySQL的自增id會用完嗎?用完怎么辦
MySQL作為最常用的關系型數(shù)據(jù)庫,無論是在應用還是在面試中都是必須掌握的技能。
一、MySQL自增主鍵會用完嗎
我們在使用MySQL設置的自增主鍵的時候,一般都是定義初始值和定義步長,我們知道自然數(shù)是沒有上限的,但是MySQL的自增主鍵是會設置字節(jié)長度的,但凡有字節(jié)長度那么就會有上限。
二、MySQL自增主鍵用完會怎樣
不管我們設置字節(jié)長度為多大,如果假設MySQL運行時間足夠長,那么就一定會用完,對于MySQL的情況會分為兩種:
1.程序員自己設置的自增主鍵。
毫無疑問,當數(shù)值達到最大時候,再去獲取自增主鍵得到的依然是最大值,插入的時候就會報主鍵沖突。這個是在server層實現(xiàn)的。
2.程序員沒有設置自增主鍵,mysql自動創(chuàng)建row_id。
這里需要注意,MySQL中的row_id是在引擎層實現(xiàn)的,InnoDB代碼中會創(chuàng)建一個不可見的長度為8的自增字段row_id,步長為1,但是InnoDB在實現(xiàn)的時候卻只給此字段分配6個字節(jié)的空間長度,因此在保存數(shù)據(jù)的時候只能取row_id字段的最后6字節(jié)進行保存,我們知道6字節(jié)數(shù)值最大為2的248次方,如果已經(jīng)達到這個值后,再次插入數(shù)據(jù)時候,row_id就是2的248次方加1,從這個數(shù)值中取最后6字節(jié)正好是0,而在InnoDB的實現(xiàn)邏輯中如果row_id重復,不會報主鍵沖突,而是會覆蓋原數(shù)據(jù)。
現(xiàn)在你應該清楚mysql的自增主鍵是有上限的,達到上限后就會出現(xiàn)上面說的現(xiàn)象。
三、mysql中還有哪些自增id,達到最大又會如何呢
1.max_trx_id
我們知道MySQL中,沒創(chuàng)建一個事物就會去申請一個事物id(trx_id),申請的方式就是從獲取全局變量max_trx_id當前值,然后將max_trx_id+1,max_trx_id是InnoDB內部維護的,并且是持久化保存的,也就是說即便MySQL重啟也不會重置這個值。
一般的select語句是不會申請事物id的,除非語句后面加上for update。
max_trx_id也是8個字節(jié)的長度,雖然數(shù)字足夠大,但是假設mysql運行時間足夠長,早晚也會達到最大值的,max_trx_id達到最大值后會重置為0,重新開始。
這種情況下就會有個問題,看下圖:
我們知道在可重復讀隔離級別下數(shù)據(jù)的可見性是通過事物的一致性視圖來判斷的。這種情況下就會出現(xiàn)臟讀的bug。
解釋:
假設在上面sql執(zhí)行前系統(tǒng)的max_trx_id已經(jīng)是最大值999(假設這是最大值),所以在session A啟動的事務的低水位就是999。
在T2時刻,session B執(zhí)行第一條update語句的事務id就是999,而第二條update語句的事務id就是0了,這條update語句執(zhí)行后生成的數(shù)據(jù)版本上的trx_id就是0。
在T3時刻,session A執(zhí)行select語句的時候,判斷可見性發(fā)現(xiàn),c=3這個數(shù)據(jù)版本的trx_id,小于sessionA的事務低水位,因此認為這個數(shù)據(jù)可見。
但實際sessionA不應該看到c=3這條數(shù)據(jù),因此出現(xiàn)這個是臟讀。
這是MySQL必現(xiàn)的一個bug。
2.thread_id
thread_id是MySQL中常見的一種自增id,長度為4個字節(jié),當達到最大值時就會重置為0,重新開始,但是我們在日常的維護中用show processlist查看的時候從來都不會看到重復的id,這是因為MySQL在實現(xiàn)的時候做了一些操作,代碼如下:
do {
new_id= thread_id_counter++;
} while (!thread_ids.insert_unique(new_id).second);
因此MySQL中的thread_id不會出現(xiàn)重復。
mysql中還有一些其他的自增id,比如mysql中還有redo log和binlog相關的xid,binlog文件序號,還有table_id等。但是我們最應該知道就是上面這幾個,其他的感興趣可以隨時來找我探討。