Mysql auto_increment總結


一、為什么InnoDB表要建議用自增列做主鍵

我們先了解下InnoDB引擎表的一些關鍵特征:

  • InnoDB引擎表是基於B+樹的索引組織表(IOT);
  • 每個表都需要有一個聚集索引(clustered index);
  • 所有的行記錄都存儲在B+樹的葉子節點(leaf pages of the tree);
  • 基於聚集索引的增、刪、改、查的效率相對是最高的;
  • 如果我們定義了主鍵(PRIMARY KEY),那么InnoDB會選擇其作為聚集索引;
  • 如果沒有顯式定義主鍵,則InnoDB會選擇第一個不包含有NULL值的唯一索引作為主鍵索引;
  • 如果也沒有這樣的唯一索引,則InnoDB會選擇內置6字節長的ROWID作為隱含的聚集索引(ROWID隨着行記錄的寫入而主鍵遞增,這個ROWID不像ORACLE的ROWID那樣可引用,是隱含的)。

綜上總結,如果InnoDB表的數據寫入順序能和B+樹索引的葉子節點順序一致的話,這時候存取效率是最高的,也就是下面這幾種情況的存取效率最高:

  • 使用自增列(INT/BIGINT類型)做主鍵,這時候寫入順序是自增的,和B+數葉子節點分裂順序一致;
  • 該表不指定自增列做主鍵,同時也沒有可以被選為主鍵的唯一索引(上面的條件),這時候InnoDB會選擇內置的ROWID作為主鍵,寫入順序和ROWID增長順序一致;
  • 除此以外,如果一個InnoDB表又沒有顯示主鍵,又有可以被選擇為主鍵的唯一索引,但該唯一索引可能不是遞增關系時(例如字符串、UUID、多字段聯合唯一索引的情況),該表的存取效率就會比較差。

實際情況是如何呢?經過簡單TPCC基准測試,修改為使用自增列作為主鍵與原始表結構分別進行TPCC測試,前者的TpmC結果比后者高9%倍,足見使用自增列做InnoDB表主鍵的明顯好處,其他更多不同場景下使用自增列的性能提升可以自行對比測試下。

  注意:同時推薦使用UNSIGNED自增列作為主鍵。

DROP TABLE IF EXISTS `test_auto_increment`;
CREATE TABLE `test_auto_increment` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;

 

二、mysql獲取自增ID的最大值

mysql插入數據后返回自增ID的方法,last_insert_id(),selectkey

 在關系型數據庫的表結構中,一般情況下,都會定義一個具有‘AUTO_INCREMENT’擴展屬性的‘ID’字段,以確保數據表的每一條記錄都有一個唯一標識。

而實際應用中,獲取到最近最大的ID值是必修課之一,針對於該問題,實踐整理如下:

1、新建測試數據表get_max_id

-- ----------------------------
-- Table structure for test_auto_increment
-- ----------------------------
DROP TABLE IF EXISTS `test_auto_increment`;
CREATE TABLE `test_auto_increment` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;

2、未初始化表獲取最大自增ID

  創建完數據表之后,我們知道,表中的內容暫時為空,此時,查詢max(id)獲取到的內容將是NULL;

  方式1 - max(id):

    該方式的優點是簡單粗暴,直奔主題;

    同時,它無視其它客戶端連接(db_connection)的影響,可以直奔第3點位置;

select max(id) from test_auto_increment;

方式2 - LAST_INSERT_ID()函數:

  LAST_INERT_ID(),返回最后一個INSERT或 UPDATE 查詢中, AUTO_INCREMENT列設置的第一個表的值。

 這玩意兒的使用還是有些限制的:

  1、同一個Connection連接對象(同一客戶端)中,SELECT的結果為最后一次INSERT的AUTO_INCREMENT屬性列的ID。這句話的重點在於“同一個”,即其他連接的客戶端不對其查詢的結果造成影響。假設客戶端A和B,表ta原自增ID為3,在A中插入記錄后產生自增ID為4,在客戶端A中通過該函數查詢的結果為4,但在客戶端B中查詢的結果值仍為3;(已驗證)

  2、與表無關,即假設ta表和tb表,向ta插入記錄后,再向tb插入記錄,結果值為tb的max(id)值;(已驗證)

  3、使用非魔術方法(‘magic‘)來INSERT或UPDATE一條記錄時,即使用非0/非NULL值作為插入的字段,則LAST_INSERT_ID()返回值不會發生變化;(已驗證)

  4、同一條INSERT語句中,傳入多個VALUES值,則LAST_INSERT_ID()返回值為該查詢第一條記錄的ID;(已驗證)

    5、在進階方面,可運用作分表ID的唯一性。

    初始化查詢的結果,得到的是0,這點和max(id)還是有區別的;

mysql>select LAST_INSERT_ID();
 +------------------+
 | LAST_INSERT_ID() |
 +------------------+
 |                0 |
 +------------------+
 1 row in set (0.00 sec)

方式3 - 查看表狀態show table status

    該方式提供了當前DB(use db_name;)下每個表的基本信息;可以通過where條件獲取到Auto_increment屬性的值;

    下述提供的結果值,為下一個自增ID的數值。

mysql> show table status where Name=‘get_max_id‘;
+------------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+-----------------+----------+----------------+---------+
| Name       | Engine | Version | Row_format | Rows | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Auto_increment | Create_time         | Update_time | Check_time | Collation       | Checksum | Create_options| Comment |
+------------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+-----------------+----------+----------------+---------+
| get_max_id | InnoDB |      10 | Compact    |    0 |              0 |       16384 |               0 |            0 |  10485760 |              1 | 2015-04-20 11:49:07 | NULL        | NULL       | utf8_general_ci |     NULL |     |         |
+------------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+-----------------+----------+----------------+---------+
1 row in set (0.00 sec)

  方式4 - information_schema.tables

    提供關於數據庫中的表(包括視圖)的信息。詳細描述了某個表屬於哪個schema,表類型,表引擎等等信息;

    下述提供的結果值,為下一個自增ID的數值。

mysql> select table_name, AUTO_INCREMENT from information_schema.tables where table_name="get_max_id";
+------------+----------------+
| table_name | AUTO_INCREMENT |
+------------+----------------+
| get_max_id |              1 |
+------------+----------------+
1 row in set (0.01 sec)

方式5 - @@IDENTITY全局變量

    基礎:以@@開頭的變量為全局變量,而以@開頭的變量為用戶自定義的變量。

    此處 @@IDENTITY表示最近一次向具有identity屬性(auto_increment)的表INSERT數據時對應的自增列的值。此處得到的值是0。

    1、類似於LAST_INSERT_ID()函數,該方式必須在同一個客戶端內進行的INSERT與SELECT,且不受其他客戶端影響;(已驗證)

    2、與表無關;(已驗證)

    3、非魔術方法插入不影響結果值;(已驗證)

    4、同一INSERT插入多條記錄,取第一條記錄的ID值為結果;(已驗證)

mysql> select @@IDENTITY;
+------------+
| @@IDENTITY |
+------------+
|          0 |
+------------+
1 row in set (0.00 sec)

 

三、自增ID在服務器重啟后會根據表中當前最大值重新計算

驗證如下:

1、先向測試表插入如下行

2、刪除2-6的行,再插入新的7行數據,如下所示,ID繼續增長

3、刪除最后的5行數據

4、重啟mysql

5、插入新的數據


免責聲明!

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



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