mysql 自增值&自增鎖

 

參考:《mysql內核:innodb存儲引擎》 第九章

            mysql實戰45講—自增主鍵爲什麼不是連續的?

            [MySQL源碼] Innodb如何處理auto_inc值:https://yq.aliyun.com/articles/40926

            [MySQL Bug]bug#61209簡析:https://yq.aliyun.com/articles/40929

 

 

測試環境:Mysql 5.6.43版本

 

 

 

 

--2、上述5個問題的測試


--數據庫參數設置
mysql> show variables like '%auto_increment%';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| auto_increment_increment | 10    |    //自增值遞增的間隔,測試設置值爲 10
| auto_increment_offset    | 5     |    //自增值的起始偏移,測試設置值爲 5
+--------------------------+-------+
2 rows in set (0.00 sec)

mysql> show variables like '%innodb_autoinc_lock_mode%';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| innodb_autoinc_lock_mode | 1     |    //申請後立即釋放,但批量操作  比如 insert...select  、load data 之類的操作  還是回退到0的方式 即提交結束後 釋放自增鎖
+--------------------------+-------+
1 row in set (0.00 sec)


--創建測試表並測試數據,id爲自增值 ,以5位偏移量  、每次自增10
mysql> create table test_table_autoincr
      (id int   auto_increment,
      name varchar(10),
      id_card int,
      primary key(id),
      unique key idx_test_table_autoincr_id_card(id_card)
      )engine=innodb;
Query OK, 0 rows affected (0.22 sec)

--插入測試數據
insert into test_table_autoincr values (null,'aa',11);
commit;


--如上問題1的現象:數據庫重啓後,會取得該表的最大自增值(SELECT MAX(col_name) FROM TABLE) +1 賦給下一條記錄,可能會造成自增值的回退
--插入待刪除的name=aa_del的一條數據,然後刪除
insert into test_table_autoincr values (null,'aa_del',1111);
commit;

mysql> delete from test_table_autoincr where id=15;
mysql> commit;

mysql> select * from test_table_autoincr;
+----+------+---------+
| id | name | id_card |
+----+------+---------+
|  5 | aa   |      11 |
+----+------+---------+
1 row in set (0.00 sec)

--查看下個自增值爲AUTO_INCREMENT=25,因上個自增值爲15的值被刪除了
mysql> show create table test_table_autoincr\G
*************************** 1. row ***************************
       Table: test_table_autoincr
Create Table: CREATE TABLE `test_table_autoincr` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(10) COLLATE utf8_bin DEFAULT NULL,
  `id_card` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_test_table_autoincr_id_card` (`id_card`)
) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=utf8 COLLATE=utf8_bin
1 row in set (0.00 sec)

--重啓數據庫
[root@localmysql-source ~]# service mysql restart
Shutting down MySQL....[  OK  ]
Starting MySQL.[  OK  ]

--自增值回退爲AUTO_INCREMENT=6  也就是該表的最大自增值(SELECT MAX(col_name) FROM TABLE) +1  (即是目前自增值的間隔是10的情況下 也是+1,下次插入自增值時 會重新計算 )
mysql> show create table test_table_autoincr\G
*************************** 1. row ***************************
       Table: test_table_autoincr
Create Table: CREATE TABLE `test_table_autoincr` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(10) COLLATE utf8_bin DEFAULT NULL,
  `id_card` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_test_table_autoincr_id_card` (`id_card`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COLLATE=utf8_bin
1 row in set (0.00 sec)

--繼續插入數據 
insert into test_table_autoincr values (null,'bb',22),(null,'cc',33),(null,'dd',44);
commit;

--查看當前表數據,發現自增值連續,不受到之前delete數據的影響
mysql> select * from test_table_autoincr;
+----+------+---------+
| id | name | id_card |
+----+------+---------+
|  5 | aa   |      11 |
| 15 | bb   |      22 |
| 25 | cc   |      33 |
| 35 | dd   |      44 |
+----+------+---------+
4 rows in set (0.00 sec)


--查看錶狀態,可看下個自增值爲AUTO_INCREMENT=45
mysql> show create table test_table_autoincr\G
*************************** 1. row ***************************
       Table: test_table_autoincr
Create Table: CREATE TABLE `test_table_autoincr` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(10) COLLATE utf8_bin DEFAULT NULL,
  `id_card` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_test_table_autoincr_id_card` (`id_card`)
) ENGINE=InnoDB AUTO_INCREMENT=45 DEFAULT CHARSET=utf8 COLLATE=utf8_bin
1 row in set (0.00 sec)




--如上問題2的現象:id_card唯一索引衝突後,下一條自增值不連續了。 45的自增值因唯一索引衝突而丟失
mysql> insert into test_table_autoincr values (null,'ee',44);
ERROR 1062 (23000): Duplicate entry '44' for key 'idx_test_table_autoincr_id_card'

mysql> insert into test_table_autoincr values (null,'ee',55);

mysql> select * from test_table_autoincr;
+----+------+---------+
| id | name | id_card |
+----+------+---------+
|  5 | aa   |      11 |
| 15 | bb   |      22 |
| 25 | cc   |      33 |
| 35 | dd   |      44 |
| 55 | ee   |      55 |
+----+------+---------+
5 rows in set (0.00 sec)



--如上問題3的現象:事務回滾後,下一條自增值不連續了。65的自增值因爲回滾而丟失
mysql> begin;
mysql> insert into test_table_autoincr values (null,'ff',66);
mysql> rollback;

mysql> insert into test_table_autoincr values (null,'ff',66);
mysql> commit;

mysql> select * from test_table_autoincr;
+----+------+---------+
| id | name | id_card |
+----+------+---------+
|  5 | aa   |      11 |
| 15 | bb   |      22 |
| 25 | cc   |      33 |
| 35 | dd   |      44 |
| 55 | ee   |      55 |
| 75 | ff   |      66 |
+----+------+---------+
6 rows in set (0.00 sec)




--如上問題4的現象:插入給定的自增值505,會造成和上一條的75自增值不連續了。
mysql> insert into test_table_autoincr values (505,'gg',77);
mysql> insert into test_table_autoincr values (null,'hh',88);
mysql> commit;

mysql> select * from test_table_autoincr;
+-----+------+---------+
| id  | name | id_card |
+-----+------+---------+
|   5 | aa   |      11 |
|  15 | bb   |      22 |
|  25 | cc   |      33 |
|  35 | dd   |      44 |
|  55 | ee   |      55 |
|  75 | ff   |      66 |
| 505 | gg   |      77 |
| 515 | hh   |      88 |
+-----+------+---------+
8 rows in set (0.00 sec)

--其中如果不是按照自增值間隔和偏移量的規律來的話, 會造成和上一條以及下一條的自增值同時不連續了。  插入1000後 不符合自增長間隔和偏移量,下一條自增值要符合規律變爲1005 造成不連續
mysql> insert into test_table_autoincr values (1000,'ii',99);
mysql> insert into test_table_autoincr values (null,'jj',110);
mysql> insert into test_table_autoincr values (null,'kk',220);
mysql> commit;

mysql>  select * from test_table_autoincr;
+------+------+---------+
| id   | name | id_card |
+------+------+---------+
|    5 | aa   |      11 |
|   15 | bb   |      22 |
|   25 | cc   |      33 |
|   35 | dd   |      44 |
|   55 | ee   |      55 |
|   75 | ff   |      66 |
|  505 | gg   |      77 |
|  515 | hh   |      88 |
| 1000 | ii   |      99 |
| 1005 | jj   |     110 |
| 1015 | kk   |     220 |
+------+------+---------+
11 rows in set (0.00 sec)




--如上問題5的現象:批量插入時,會分配的自增值個數爲上一次的2倍, 這樣分配下來 會造成一些自增值浪費 造成下一條自增值不連續了。
--測試表test_table_autoincr_2 插入4條數據,分四次申請的,第一次申請1個,第二次申請2個,第三次申請4個,這樣就是申請了7個 但實際只有4條數據,
create table test_table_autoincr_2 like test_table_autoincr;
insert into test_table_autoincr_2 values (null,'qwer',1111);
insert into test_table_autoincr_2 values (null,'adsf',2222);
insert into test_table_autoincr_2 values (null,'zxcv',3333);
insert into test_table_autoincr_2 values (null,'uiop',4444);
commit;
mysql> select * from test_table_autoincr_2;
+----+------+---------+
| id | name | id_card |
+----+------+---------+
|  5 | qwer |    1111 |
| 15 | adsf |    2222 |
| 25 | zxcv |    3333 |
| 35 | uiop |    4444 |
+----+------+---------+
4 rows in set (0.00 sec)


mysql> show create table test_table_autoincr_2\G
*************************** 1. row ***************************
       Table: test_table_autoincr_2
Create Table: CREATE TABLE `test_table_autoincr_2` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(10) COLLATE utf8_bin DEFAULT NULL,
  `id_card` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_test_table_autoincr_id_card` (`id_card`)
) ENGINE=InnoDB AUTO_INCREMENT=45 DEFAULT CHARSET=utf8 COLLATE=utf8_bin
1 row in set (0.00 sec)




--測試表test_table_autoincr_3複製test_table_autoincr_2的數據後,再插入一條數據後,45、55、65自增值丟失 不連續了, 從第8個開始
create table test_table_autoincr_3 like test_table_autoincr_2;
insert into test_table_autoincr_3(name,id_card) select name,id_card from test_table_autoincr_2;

mysql> select * from test_table_autoincr_3;
+----+------+---------+
| id | name | id_card |
+----+------+---------+
|  5 | qwer |    1111 |
| 15 | adsf |    2222 |
| 25 | zxcv |    3333 |
| 35 | uiop |    4444 |
+----+------+---------+
4 rows in set (0.00 sec)


mysql> show create table test_table_autoincr_3\G
*************************** 1. row ***************************
       Table: test_table_autoincr_3
Create Table: CREATE TABLE `test_table_autoincr_3` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(10) COLLATE utf8_bin DEFAULT NULL,
  `id_card` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_test_table_autoincr_id_card` (`id_card`)
) ENGINE=InnoDB AUTO_INCREMENT=75 DEFAULT CHARSET=utf8 COLLATE=utf8_bin
1 row in set (0.00 sec)


mysql> insert into test_table_autoincr_3 values (null,'hjlk',5555);
Query OK, 1 row affected (0.00 sec)


mysql> select * from test_table_autoincr_3;
+----+------+---------+
| id | name | id_card |
+----+------+---------+
|  5 | qwer |    1111 |
| 15 | adsf |    2222 |
| 25 | zxcv |    3333 |
| 35 | uiop |    4444 |
| 75 | hjlk |    5555 |
+----+------+---------+
5 rows in set (0.00 sec)

 

 

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