AUTO_INCREMENT初始值和步長相關(guān)操作
查看mysql的遞增初始值和步長
SHOW VARIABLES LIKE 'auto_inc%';
查看表的當前遞增值和步長
SELECT auto_increment FROM information_schema.tables where table_schema='test' and table_name='id_lock';
mysql只能對mysql實例級別修改,不能對表修改
SET @@auto_increment_increment=3; -- 將自增長步長設(shè)置為3
SET @@auto_increment_offset=4; -- 將自增長開始值設(shè)置為4
mysql中AUTO_INCREMENT的主鍵字段在什么時候會觸發(fā)遞增?
在執(zhí)行insert語句之后,而不是在insert語句所在事務(wù)提交之后。這樣可以提高主鍵生成在并發(fā)下的性能。我們可以做個實驗了驗證。
事務(wù)A
mysql> set @@autocommit =1; step1
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO `test`.`id_lock`(`id`) VALUES (NULL); step2
Query OK, 1 row affected (0.13 sec)
mysql> INSERT INTO `test`.`id_lock`(`id`) VALUES (NULL); step6
Query OK, 1 row affected (0.00 sec)
mysql> select * from id_lock; step7
+----+
| id |
+----+
| 1 |
| 3 |
+----+
2 rows in set (0.03 sec)
mysql>
事務(wù)B
mysql> set @@autocommit = 1; step3
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO `test`.`id_lock`(`id`) VALUES (NULL); step4
Query OK, 1 row affected (0.00 sec)
mysql> select * from id_lock; step5
+----+
| id |
+----+
| 2 |
+----+
1 row in set (0.03 sec)
mysql>
可以看到,事務(wù)A和B都沒有commit ,它們的自增當前值互相受影響。有點像RU讀未提交的隔離級別下出現(xiàn)的"臟讀"。然而這里允許讀到已經(jīng)其它事務(wù)未提交的自增當前值。這樣做是為了性能考慮。所以若有些insert被回滾沒有生效,就會導(dǎo)致記錄不是連續(xù)的,中間有個別空缺不連續(xù)。
自增主鍵存在的性能問題
對于高并發(fā)工作負載,在InnoDB中按主鍵順序插入可能會造成明顯的爭用。
1、主鍵上界(自增的當前值)會成為”熱點”,因為所有的插入都發(fā)生在這里,所以并發(fā)插入可能導(dǎo)致間隙鎖競爭。
2、另一個熱點可能是AUTO_INCREMENT鎖機制:如果遇到這個問題,則可能需要考慮重新設(shè)計表或者應(yīng)用,或者更改innodb_autoinc_lock_mode配置。
AUTO-INC Locking機制
自增長在數(shù)據(jù)庫中是非常常見的一種屬性,也是很多DBA或開發(fā)人員首選的主鍵方式。在InnoDB存儲引擎的內(nèi)存結(jié)構(gòu)中,對每個含有自增長值的表都有一個自增長計數(shù)器。當對含有自增長的計數(shù)器的表進行插入操作時,這個計數(shù)器會被初始化,執(zhí)行如下的語句來得到計數(shù)器的值:
select max(auto_inc_col) from t for update;
插入操作會依據(jù)這個自增長的計數(shù)器值加1賦予自增長列。這個實現(xiàn)方式稱為AUTO-INC Locking。這種鎖其實是采用一種特殊的表鎖
機制,為了提高插入的性能,鎖不是在一個事務(wù)完成后才釋放,而是在完成對自增長值插入的SQL語句后立即釋放。(這個結(jié)論上文已經(jīng)做了驗證)
雖然AUTO-INC Locking從一定程度上提高了并發(fā)插入的效率,但還是存在一些性能上的問題,優(yōu)化還遠遠不夠。
1、首先,對于有自增長值的列的并發(fā)插入性能較差,事務(wù)必須等待前一個插入的完成,雖然不用等待事務(wù)的完成。
2、其次,對于INSERT….SELECT的大數(shù)據(jù)的插入會影響插入的性能,因為另一個事務(wù)中的插入會被阻塞。
mutex互斥量機制
從MySQL 5.1.22版本開始,InnoDB存儲引擎中提供了一種輕量級互斥量
的自增長實現(xiàn)機制,這種機制大大提高了自增長值插入的性能。并且從該版本開始,InnoDB存儲引擎提供了一個參數(shù)innodb_autoinc_lock_mode
來控制自增長的模式,該參數(shù)的默認值為1。在繼續(xù)討論新的自增長實現(xiàn)方式之前,需要對自增長的插入進行分類。插入操作可以根據(jù)是否能確定得到插入行數(shù)
分為下面四個類別:
1、insert-like:指所有的插入語句,如INSERT、REPLACE、INSERT…SELECT,REPLACE…SELECT、LOAD DATA等。
2、simple inserts:指能在插入前就確定插入行數(shù)的語句,這些語句包括INSERT、REPLACE等。需要注意的是:simple inserts不包含INSERT…ON DUPLICATE KEY UPDATE、INSERT IGNORE這類SQL語句。
3、bulk inserts:指在插入前不能確定得到插入行數(shù)的語句,如INSERT…SELECT,REPLACE…SELECT,LOAD DATA、INSERT IGNORE。
4、mixed-mode inserts:混合的,指插入中有一部分的值是自增長的,有一部分是確定的主鍵值(不會觸發(fā)自鎮(zhèn)長)。如INSERT INTO t1(c1,c2) VALUES(1,’a’),(2,’a’),(null,’a’);也可以是指INSERT…ON DUPLICATE KEY UPDATE這類SQL語句。
innodb_autoinc_lock_mode參數(shù)
接下來分析參數(shù)innodb_autoinc_lock_mode以及各個設(shè)置下對自增長的影響,其總共有三個有效值可供設(shè)定,即0、1、2,具體說明如下:
0, traditional
1, consecutive
2, interleaved
0:這是MySQL 5.1.22版本之前自增長的實現(xiàn)方式,即通過表鎖的AUTO-INC Locking方式,因為有了新的自增長實現(xiàn)方式,0這個選項不應(yīng)該是新版用戶的首選了。
①、這種模式下,所有的insert語句在開始時都會獲得一個表鎖AUTO-INC Locking。該鎖會一直持有到insert語句執(zhí)行結(jié)束才會被釋放。
②、對于一條insert插入多個行記錄的語句,他保證了同一條語句插入的行記錄的自增ID是連續(xù)的。
③、這個鎖并不是事務(wù)級別的鎖。在這種模式下,主從復(fù)制時,基于語句復(fù)制模式下,主和從的同一張表的同一個行記錄的自增ID是一樣的。這種模式下,表的并發(fā)性最低。(性能最差,但主從下不會導(dǎo)致id不一致)
1:這是該參數(shù)的默認值,對于”simple inserts”,該值會用互斥量(mutex)去對內(nèi)存中的計數(shù)器進行累加的操作。
①、這種模式下,insert語句在開始時會獲得一個表鎖AUTO-INC Locking,
simple insert在獲取到需要增加的ID的量后,autoinc_lock就會被釋放,不必等到語句執(zhí)行結(jié)束
。
②、但對于bulk insert,自增鎖會被一直持有直到語句執(zhí)行結(jié)束才會被釋放。
③、這種模式仍然保證了同一條語句插入的行記錄的自增ID是連續(xù)的。這種模式下的主從復(fù)制表現(xiàn)跟traditional模式下一樣,也不會導(dǎo)致主從id不一致,但是性能會有所提高。
④、需要注意的是,如果已經(jīng)使用AUTO-INC Locing方式去產(chǎn)生自增長的值,而這時需要再進行”simple inserts”的操作時,還是需要等待AUTO-INC Locking的釋放。
2:在這個模式下,對于所有的插入操作”INSERT-LIKE”自增長值的產(chǎn)生都是通過互斥量,而不是AUTO-INC Locking的方式。不管什么情況都使用輕量級互斥的鎖。
①、顯然,
innodb_autoinc_lock_mode=2 是性能最高的方式
。然而,這會帶來一定的問題。
②、因為并發(fā)插入的存在,在每次插入時,自增長的值可能不是連續(xù)的。
③、此外,最重要的是,基于Statement的主從復(fù)制會出現(xiàn)問題。因此,使用這個模式,任何時候都應(yīng)該使用Row方式。這樣才能保證最大的并發(fā)性能及主從數(shù)據(jù)的一致。
(innodb_autoinc_lock_mode=2 性能最好,代價是自增值可能不連續(xù)。而且會讓基于Statement的主從復(fù)制出現(xiàn)id不一致問題,此時需使用Row的方式)
SHOW VARIABLES LIKE 'innodb_autoinc_lock_mode'
[mysqld]
innodb_autoinc_lock_mode = 2
總結(jié)
1、innodb row復(fù)制時,可將innodb_autoinc_lock_mode設(shè)置為2,這時可在所有insert情況下表獲得最大并發(fā)度。
2、innodb statement復(fù)制時,可將innodb_autoinc_lock_mode設(shè)置為1,保證復(fù)制安全的同時,獲得簡單insert語句的最大并發(fā)度。
3、myisam引擎情況下,無論什么樣自增id鎖都是表級鎖,設(shè)置innodb_autoinc_lock_mode參數(shù)無效。
4、mysql 5.7默認AUTO_INCREMENT為1,我們將之設(shè)置為2可以提高性能。當然mysql8中已經(jīng)默認是2了