InnoDB如何處理AUTO_INCREMENT

InnoDB提供一個優化,當向帶有auto_increment列的表中插入數據時,可以顯著提高表的可擴展性和性能。使用AUTO_INCREMENT機制的InnoDB表,一個AUTO_INCREMENT列ai_col 必須被定義爲索引的一部分分,這樣當執行SELECT MAX(ai_col)查詢以獲得最大行數值時,纔可以利用索引獲得。典型的,由表的第一列來實現。

這部分提供了內部信息,InnoDB中關於傳統方法實現AUTO_INCREMENT鎖。講解配置鎖機制,說明配置機制參數。描述他的行爲和複製中的交互。

傳統InnoDB AUTO_INCREMENT 鎖

InnoDB中,AUTO_INCREMENT 處理實現的原理,是使用下面的策略阻止問題發生,並且當使用基於二進制日誌複製或某些回覆場景。

如果你爲InnoDB表指定一個AUTO_INCREMENT列,表中處理InnoDB數據字典包含一個指定的計數器,名字叫做AUTO_INCREMENT 計數器,用來給列分配新的值。這個計數器僅僅被存儲在內存中,而不是在硬盤上。

InnoDB 使用下面的算法去初始化AUTO_INCREMENT計數器,表T中包含一個AUTO_INCREMENT列,名稱是ai_col. 在服務器啓動或打開一個表後,它被從表緩存中剔除,InnoDB相當於執行這條語句插入表:

select max(ai_col) from table_name for update;

InnoDB 增加值被語句獲取到並且把該值分配給列是通過表的AUTO_INCREMENT計數器。 默認情況下,值每次自增量爲1. 這個默認的值可以被auto_increment_increment配置選項修改。

備註:

auto_increment_increment:控制連續列之間數值的差額。如果該值設置爲10,第一行的值假設爲11,第二行的自增列值爲11+10-21.

auto_increment_offset: 控制表初始第一行的自增列的值。如果設置2,則插入第一次的自增值爲2. 第二行的值爲2+auto_increment_increment值。這裏要注意,不是表第一行的值爲2,而是第一次插入的值爲2.

備註:如果auto_increment_offset大於auto_increment_increment,auto_increment_offset的值會被或略。

如果表是空的,InnoDB 使用值爲1,這個默認操作可以被auto_increment_offset配置選項修改。

如果在auto-increment計數器被初始化之前,執行了SHOW TABLE STATUS檢查表t,InnoDB初始化但不會自增數值和存儲它。這個初始化使用普通的排外讀鎖並且鎖住最後的事務。

當然,我們可以在創建表時,指定auto-increment的初始值,比如:

CREATE TABLE `a` (

`c1` int(11) NOT NULL AUTO_INCREMENT,

`c2` varchar(20) DEFAULT NULL,

PRIMARY KEY (`c1`)

) ENGINE=InnoDB AUTO_INCREMENT=100 DEFAULT CHARSET=utf8

InnoDB 爲一個新表使用相同的存儲過程初始化自增計數器。

在自增計數器被初始化後,如果你沒有明確指定爲自增列指定一個值,InnoDB自增計數器會分配一個新值爲列。如果你在插入式明確指定列值,並且只大於當前的計數器的值,計數器將被設置爲指定的列值。

在insert語句中,如果用戶指定NULL或0,InnoDB認爲該行沒有被指定數值並且自動生成一個新的值給它。

自增機制的行爲沒有被定義,如果你分配一個負數值給列或如果值大於整數的最大值,那麼將被保存到指定的整數類型。

當訪問自增計數器,InnoDB使用一個指定的表級auto-inc鎖,這樣它一直保持到當前語句結束,不是事務結束。指定的鎖釋放策略被介紹用了提升併發插入能力。然而,兩個事務不能同時在相同的表上有auto-inc鎖。 這個會導致性能影響,如果auto-inc鎖被佔用很長時間的話。比如這種情況,例如語句:

insert into t1 ... select .... from t2

這種情況會把t2的所有行插入到t1表中。

InnoDB的自增計數器一直存在內存中, 當服務器被重啓或關閉,InnoDB 會重新初始化計數器爲每個表當第一次執行insert操作的時候。

在CREATE TABLE and ALTER TABLE語句中,服務器重啓也取消AUTO_INCREMENT = N對錶選項的影響,對於InnoDB表,你可以設置初始值或修改當前值。

如果你回滾了事務,在自增列上,你可以看到自增值的gaps,即自增列的值不是連續的。

Configurable InnoDB Auto-Increment Locking

如前面部分描述,InnoDB使用指定的表級鎖auto-inc爲插入帶有auto_increment 列的表。這個鎖通常一直保持到語句結束(不是事務)。目的是對於一個給定的insert 語句,爲了保證自增數字被分配是可預見的和可重複的。

在基於語句的複製情況下,這意味着當SQL語句被複制到一個slave服務器上是,自增列的值和master服務器是相同的。多個insert語句的執行結果是可以確定的,並且slave會生成和master相同的數據。如果自增值被多個insert語句交替產生,如果兩個insert語句同時被執行,結果將是不確定的。這將導致使用基於語句的複製變得不可靠。

由於使用表級鎖,導致併發和擴擴展性受限制。

新的鎖機制將解決這個問題。用以提高高併發下的插入問題。引入了參數innodb_autoinc_lock_mode。下面的情況需要考慮的:

1、“insert - like”statements

這些語句將產生很多新的行:insert,insert ... select,replace,replace ... select 和 load data

2、“sample inserts”

插入的行數可以在插入之前就知道的。包括單一行和多行。

3、“Bulk inserts”

插入之前不知道有多少行數據。這樣InnoDB每次插入一行就分配一個自增值。

4、“Mixed-mode inserts”

插入之前有部分行數是知道的,有部分是不知道的。

innodb_autoinc_lock_mode有3個參數:

innodb_autoinc_lock_mode = 0 (“traditional” lock mode)

innodb_autoinc_lock_mode = 1 (“consecutive” lock mode)

這是默認的模式。除了對單行數據插入不用表鎖,其他都用表級鎖lock-anc

innodb_autoinc_lock_mode = 2 (“interleaved” lock mode)

這種模式,沒有語句使用表級鎖,多個語句可以同時執行。這是最快和最擴展性的鎖模式。當使用基於語句複製模式並且基於binlog恢復實現同步機制時,它是不安全的。

innodb_autoinc_lock_mode有幾個使用影響:

1、複製時採用自增

採用基於語句複製時,如果innodb_autoinc_lock_mode設置爲0或1,則slave上的數值和master相同。如果是2,則有可能不同。

如果採用基於行或mixed複製,0,1,2都是安全的。

2、“丟失”自增值和順序間隙

在所有模式中,如果一個事務回滾,這些自增值將被“丟失”。如果自增列的值被分配,它將不能回滾(指這個值不能回滾,不是指事務)。被“丟失”的值不能再被使用。因此,纔會在表中產生很多gaps。

3、Gaps in auto-increment values for “bulk inserts”

當模式爲0或1時,自增值會被連續的生成,因爲是表級鎖。只有一個語句可以同時執行。而當2時,纔會有gaps產生,如果有多個語句同時執行的話。

4、Auto-increment values assigned by “mixed-mode inserts”

如果在插入語句中指定自增值,而不是由計數器分配值,將導致值的分配出現問題。最好不要這樣操作。如果要看具體的案例,查詢官方手冊:14.5.5 最後部分。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章