Mysql數據庫之auto_increment


一、概述

    在數據庫應用中,我們經常需要用到自動遞增的唯一編號來標識記錄。在MySQL中,可通過數據列的auto_increment屬性來自動生成。可在建表時可用“auto_increment=n”選項來指定一個自增的初始值。可用“alter table table_name auto_increment=n”命令來重設自增的起始值,當然在設置的時候Mysql會取數據表中auto_increment列的最大值 + 1與n中的較大者作為新的auto_increment值。

    Myql的auto_increment屬性具有以下特性:

    • 具有auto_increment屬性的數據列應該是一個正數序列,如果把該數據列聲明為UNSIGNED,這樣序列的編號個數可增加一倍。比如tinyint數據列的最大編號是127,如果加上UNSIGNED,那么最大編號變為255
    • auto_increment數據列必須有唯一索引,以避免序號重復;必須具備NOT NULL屬性

    實際應用中發現,在delete掉某張innoDB表的全部數據並重啟Mysql會導致該表的auto_increment列變為1。特測試多種情況下auto_increment列的變化並記錄如下。

二、實驗

   1、innoDB與MyISAM對比

  (1)首先,創建一張引擎為innoDB的表測試一下delete掉所有數據然后重啟Mysql之后,auto_increment的情況:

mysql> CREATE TABLE `table1` (
    -> `id` bigint(20) NOT NULL auto_increment,
    -> `create_time` datetime DEFAULT NULL,
    -> PRIMARY KEY (`id`)
    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected

mysql> insert into table1(create_time) values (now());
Query OK, 1 row affected

mysql> insert into table1(create_time) values (now());
Query OK, 1 row affected

mysql> insert into table1(create_time) values (now());
Query OK, 1 row affected

mysql> insert into table1(create_time) values (now());
Query OK, 1 row affected

mysql> insert into table1(create_time) values (now());
Query OK, 1 row affected

mysql> select * from table1;
+----+---------------------+
| id | create_time         |
+----+---------------------+
|  1 | 2017-02-28 16:25:11 |
|  2 | 2017-02-28 16:25:21 |
|  3 | 2017-02-28 16:25:23 |
|  4 | 2017-02-28 16:25:23 |
|  5 | 2017-02-28 16:25:24 |
|  6 | 2017-02-28 16:25:26 |
+----+---------------------+
6 rows in set

mysql> delete from table1;
Query OK, 6 rows affected

mysql> select * from table1;
Empty set

mysql> select auto_increment from information_schema.tables where table_schema = database() and table_name='table1';
 
+----------------+
| auto_increment |
+----------------+
|              7 |
+----------------+
1 row in set

    可見,執行delete操作清空表之后,表table1的auto_increment值仍然是正常的。重啟數據庫之后:

mysql> select auto_increment from information_schema.tables where table_schema = database() and table_name='table1'; 
+----------------+
| auto_increment |
+----------------+
|              1 |
+----------------+
1 row in set

     可見,table1表的auto_increment值變成了1。

     結論:innoDB引擎的表,在執行delete清空操作之后,表的auto_increment值不會受到影響;一旦重啟Mysql數據庫,那么auto_increment值將變成1!

  (2)下面我們創建一個引擎為MyISAM的表,測試delete掉所有數據,並重啟數據庫之后auto_increment的值如何變化:

mysql> CREATE TABLE `table2` (
    -> `id` bigint(20) NOT NULL auto_increment,
    -> `create_time` datetime DEFAULT NULL,
    -> PRIMARY KEY (`id`)
    -> ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Query OK, 0 rows affected

mysql> insert into table2(create_time) values (now());
Query OK, 1 row affected

mysql> 
mysql> 
mysql> insert into table2(create_time) values (now());
Query OK, 1 row affected

mysql> insert into table2(create_time) values (now());
Query OK, 1 row affected

mysql> insert into table2(create_time) values (now());
Query OK, 1 row affected

mysql> insert into table2(create_time) values (now());
Query OK, 1 row affected

mysql> insert into table2(create_time) values (now());
Query OK, 1 row affected

mysql> select * from table2;
+----+---------------------+
| id | create_time         |
+----+---------------------+
|  1 | 2017-02-28 17:05:22 |
|  2 | 2017-02-28 17:05:25 |
|  3 | 2017-02-28 17:05:26 |
|  4 | 2017-02-28 17:05:27 |
|  5 | 2017-02-28 17:05:28 |
|  6 | 2017-02-28 17:05:29 |
+----+---------------------+
6 rows in set

mysql> delete from table2;
Query OK, 6 rows affected

mysql> select * from table2;
Empty set

mysql> select auto_increment from information_schema.tables where table_schema = database() and table_name='table2'; 
+----------------+
| auto_increment |
+----------------+
|              7 |
+----------------+
1 row in set

    delete清空操作並不會對table2的auto_increment產生任何影響。重啟數據庫之后:

mysql> select auto_increment from information_schema.tables where table_schema = database() and table_name='table2'; 
+----------------+
| auto_increment |
+----------------+
|              7 |
+----------------+
1 row in set

   可見,表table2的auto_increment仍然為7。

   結論:MyISAM引擎的表,在執行delete操作之后,表的auto_increment值不會受到影響;重啟Mysql數據庫,auto_increment值也不會受到影響!

   2、創建表時指定auto_increment

   本節我們測試創建innoDB引擎的表時指定auto_increment會不會對auto_increment產生影響:

mysql> CREATE TABLE `table3` (
    -> `id` bigint(20) NOT NULL auto_increment,
    -> `create_time` datetime DEFAULT NULL,
    -> PRIMARY KEY (`id`)
    -> ) ENGINE=InnoDB auto_increment=1000 DEFAULT CHARSET=utf8;
Query OK, 0 rows affected

mysql> select auto_increment from information_schema.tables where table_schema = database() and table_name='table3';
+----------------+
| auto_increment |
+----------------+
|           1000 |
+----------------+
1 row in set

mysql> insert into table3(create_time) values (now());
Query OK, 1 row affected

mysql> insert into table3(create_time) values (now());
Query OK, 1 row affected

mysql> insert into table3(create_time) values (now());
Query OK, 1 row affected

mysql> insert into table3(create_time) values (now());
Query OK, 1 row affected

mysql> insert into table3(create_time) values (now());
Query OK, 1 row affected

mysql> select * from table3;
+------+---------------------+
| id   | create_time         |
+------+---------------------+
| 1000 | 2017-02-28 17:15:13 |
| 1001 | 2017-02-28 17:15:14 |
| 1002 | 2017-02-28 17:15:15 |
| 1003 | 2017-02-28 17:15:15 |
| 1004 | 2017-02-28 17:15:16 |
+------+---------------------+
5 rows in set

mysql> delete from table3;
Query OK, 5 rows affected

mysql> select * from table3;
Empty set

mysql> select auto_increment from information_schema.tables where table_schema = database() and table_name='table3';
+----------------+
| auto_increment |
+----------------+
|           1005 |
+----------------+
1 row in set

     可見,delete操作並不會影響到表table3的auto_increment值。重啟數據庫之后:

mysql> select auto_increment from information_schema.tables where table_schema = database() and table_name='table3';
+----------------+
| auto_increment |
+----------------+
|              1 |
+----------------+
1 row in set

   表table3的auto_increment變成了1。

   結論:在創建innoDB表時,無論指定或不指定auto_increment,delete清空+重啟數據庫都會使表的auto_increment值變成1。

   3、delete的時候添加where 1

   本節討論在執行delete操作時,加where 1:

mysql> CREATE TABLE `table4` (
    -> `id` bigint(20) NOT NULL auto_increment,
    -> `create_time` datetime DEFAULT NULL,
    -> PRIMARY KEY (`id`)
    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected

mysql> insert into table4(create_time) values (now());
Query OK, 1 row affected

mysql> 
mysql> insert into table4(create_time) values (now());
Query OK, 1 row affected

mysql> insert into table4(create_time) values (now());
Query OK, 1 row affected

mysql> insert into table4(create_time) values (now());
Query OK, 1 row affected

mysql> insert into table4(create_time) values (now());
Query OK, 1 row affected

mysql> insert into table4(create_time) values (now());
Query OK, 1 row affected

mysql> insert into table4(create_time) values (now());
Query OK, 1 row affected

mysql> select * from table4;
+----+---------------------+
| id | create_time         |
+----+---------------------+
|  1 | 2017-02-28 17:21:33 |
|  2 | 2017-02-28 17:21:34 |
|  3 | 2017-02-28 17:21:35 |
|  4 | 2017-02-28 17:21:36 |
|  5 | 2017-02-28 17:21:36 |
|  6 | 2017-02-28 17:21:37 |
|  7 | 2017-02-28 17:21:38 |
+----+---------------------+
7 rows in set

mysql> delete from table4 where 1;
Query OK, 7 rows affected

mysql> select auto_increment from information_schema.tables where table_schema = database() and table_name='table4';
+----------------+
| auto_increment |
+----------------+
|              8 |
+----------------+
1 row in set

   重啟數據庫之后:

mysql> select auto_increment from information_schema.tables where table_schema = database() and table_name='table4';
+----------------+
| auto_increment |
+----------------+
|              1 |
+----------------+
1 row in set

   可見,網上的所流傳的delete清空操作時添加where 1並沒用。

   結論:delete innoDB表時,添加或不添加where 1,在數據庫重啟之后auto_increment都會被重置為1。

    4、如果表中有數據,但是數據id小於auto_increment會怎么樣?

   本節測試當innoDB表中有數據,但是auto_increment列最大的那個值小於表的auto_increment值會怎樣。我們先插入一些數據到表中,然后刪除末尾的幾條數據:

mysql> CREATE TABLE `table5` (
    -> `id` bigint(20) NOT NULL auto_increment,
    -> `create_time` datetime DEFAULT NULL,
    -> PRIMARY KEY (`id`)
    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected

mysql> insert into table5(create_time) values (now());
Query OK, 1 row affected

mysql> insert into table5(create_time) values (now());
Query OK, 1 row affected

mysql> insert into table5(create_time) values (now());
Query OK, 1 row affected

mysql> insert into table5(create_time) values (now());
Query OK, 1 row affected

mysql> insert into table5(create_time) values (now());
Query OK, 1 row affected

mysql> insert into table5(create_time) values (now());
Query OK, 1 row affected

mysql> insert into table5(create_time) values (now());
Query OK, 1 row affected

mysql> insert into table5(create_time) values (now());
Query OK, 1 row affected

mysql> select * from table5;
+----+---------------------+
| id | create_time         |
+----+---------------------+
|  1 | 2017-02-28 17:29:29 |
|  2 | 2017-02-28 17:29:30 |
|  3 | 2017-02-28 17:29:30 |
|  4 | 2017-02-28 17:29:30 |
|  5 | 2017-02-28 17:29:31 |
|  6 | 2017-02-28 17:29:31 |
|  7 | 2017-02-28 17:29:32 |
|  8 | 2017-02-28 17:29:32 |
+----+---------------------+
8 rows in set

mysql> delete from table5 where id > 4;
Query OK, 4 rows affected

mysql> select * from table5;
+----+---------------------+
| id | create_time         |
+----+---------------------+
|  1 | 2017-02-28 17:29:29 |
|  2 | 2017-02-28 17:29:30 |
|  3 | 2017-02-28 17:29:30 |
|  4 | 2017-02-28 17:29:30 |
+----+---------------------+
4 rows in set

mysql> select auto_increment from information_schema.tables where table_schema = database() and table_name='table5';
+----------------+
| auto_increment |
+----------------+
|              9 |
+----------------+
1 row in set

    重啟數據庫之后:

mysql> select auto_increment from information_schema.tables where table_schema = database() and table_name='table5';
+----------------+
| auto_increment |
+----------------+
|              5 |
+----------------+
1 row in set

    哇塞,奇跡發生了,table5的auto_increment居然變成了5。由此我們可以得出以下結論。

    結論:Mysql數據庫在重啟之后,innoDB表的auto_increment值將會被設置為表中auto_increment列的最大值 + 1。

三、深究

     為什么會出現上述情況呢?

     這是因為,Mysql數據庫的的auto_increment值是保存在內存中的,innoDB引擎的表的auto_increment在數據庫服務停止時並不會做持久化操作,Mysql會在下次數據庫重啟的時候,相當於通過執行語句:

select max(id) maxId from table;
alter table auto_increment = maxId + 1;

來設置表table的auto_increment值。

     嚴格意義上來說這是Mysql的一個bug。這個bug將會在8.0版本中得到修復。關於8.0版本的內容的情況,詳見:MySQL 8.0.0 版本發布,亮點都在這了! 以及 MySQL 8.0發布,是時候與MyISAM說再見了

     因為目前8.0版本穩定版尚未發布,所以目前為了避免被這個bug坑到,只能將引擎換為MyISAM或者從程序上去控制。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM