標籤: 公衆號文章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掛掉須要插入多少條記錄呢?
寫文章挺累的,有時候你以爲閱讀挺流暢的,那實際上是背後無數次修改的結果。若是你以爲不錯請幫忙轉發一下,萬分感謝~ 這裏是個人公衆號「咱們都是小青蛙」,裏邊有更多技術乾貨,時不時扯一下犢子,歡迎關注: