InnoDB為什么要使用auto_Increment


在Mysql表設計中,通常會使用一個與業務無關的自增列做為主鍵。
這是因為Mysql默認使用B-Tree索引,你可以簡單理解為“排好序的快速查找結構”。
如下是一個B-Tree的結構圖,2層B+樹,每個頁面的扇出為4;並有1到6五條記錄;上層記錄保存每個頁面的最小值;每個頁面通過雙向鏈表鏈接起來的;
mysql1.png當你插入記錄7時,就會發生頁面分裂:
msyql2.png
如上可見分裂產生了記錄移動,但是優化后的分裂操作無需記錄移動:
mysql3.png

在InnoDB的實現中,為每個索引頁面維護了一個上次插入的位置,以及上次的插入是遞增/遞減的標識。根據這些信息,InnoDB能夠判斷出新插入到頁面中的記錄,是否仍舊滿足遞增/遞減的約束,若滿足約束,則采用優化后的分裂策略;
所以建議使用一列順序遞增的 ID 來作為主鍵,但不必是數據庫的autoincrement字段,只要滿足順序增加即可 。很多大型應用會有順序遞增的ID生成器。
測試如下:

 
        
  1. CREATE TABLE `table1` (
  2. `id` int(10) NOT NULL AUTO_INCREMENT,
  3. `text` varchar(255) NOT NULL,
  4. PRIMARY KEY (`id`)
  5. ) ENGINE=InnoDB AUTO_INCREMENT=200001 DEFAULT CHARSET=utf8
  6.  
  7. CREATE TABLE `table2` (
  8. `id` int(10) NOT NULL,
  9. `text` varchar(255) NOT NULL,
  10. KEY `id` (`id`)
  11. ) ENGINE=InnoDB DEFAULT CHARSET=utf8


腳本如下:

 
        
  1. $link = mysql_connect('127.0.0.1', 'root', 'mckee');
  2. mysql_select_db('test', $link);
  3.  
  4. $count = 200000;
  5. $table1_data = range(1, $count);
  6. $text = 'just test!just test!just test!just test!just test!';
  7.  
  8. $time1 = get_time();
  9. foreach ($table1_data as $row) {
  10. $id = rand(1,100000000);
  11. mysql_query("insert into table1(text) values ('{$text}')");
  12. }
  13. $time2 = get_time();
  14. foreach ($table1_data as $row) {
  15. $id = rand(1,100000000);
  16. mysql_query("insert into table2(id, text) values ({$id}, '{$text}')");
  17. }
  18. $time3 = get_time();
  19.  
  20. echo 'tabe1 insert execute time:' . ($time2 - $time1) . PHP_EOL;
  21. echo 'tabe2 insert execute time:' . ($time3 - $time2) . PHP_EOL;
  22.  
  23. function get_time()
  24. {
  25. list( $usec , $sec ) = explode ( " " , microtime ());
  26. return ((float) $usec + (float) $sec );
  27. }


免責聲明!

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



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