MySQL 關鍵特性- 插入緩衝

插入緩衝是InnoDB存儲引擎關鍵特性中最令人激動的。不過,這個名字可能會讓人認爲插入緩衝是緩衝池中的一個部分。其實不然,InnoDB緩衝池中有Insert Buffer信息固然不錯,但是Insert Buffer和數據頁一樣,也是物理頁的一個組成部分。

我們知道,主鍵是行唯一的標識符,在應用程序中行記錄的插入順序是按照主鍵遞增的順序進行插入的。因此,插入聚集索引一般是順序的,不需要磁盤的隨機讀取。比如說我們按下列SQL定義的表。

  1. mysql> create table t ( id int auto_increment, 
    name varchar(30),primary key (id));  
  2. Query OK, 0 rows affected (0.14 sec) 

id列是自增長的,這意味着當執行插入操作時,id列會自動增長,頁中的行記錄按id執行順序存放。一般情況下,不需要隨機讀取另一頁執行記錄的存放。因此,在這樣的情況下,插入操作一般很快就能完成。但是,不可能每張表上只有一個聚集索引,在更多的情況下,一張表上有多個非聚集的輔助索引(secondary index)。比如,我們還需要按照name這個字段進行查找,並且name這個字段不是唯一的。即,表是按如下的SQL語句定義的:

  1. mysql> create table t ( id int auto_increment, 
    name varchar(30),primary key (id),key(name));  
  2. Query OK, 0 rows affected (0.21 sec) 

這樣的情況下產生了一個非聚集的並且不是唯一的索引。在進行插入操作時,數據頁的存放還是按主鍵id的執行順序存放,但是對於非聚集索引,葉子節點的插入不再是順序的了。這時就需要離散地訪問非聚集索引頁,插入性能在這裏變低了。然而這並不是這個name字段上索引的錯誤,因爲B+樹的特性決定了非聚集索引插入的離散性。

InnoDB存儲引擎開創性地設計了插入緩衝,對於非聚集索引的插入或更新操作,不是每一次直接插入索引頁中。而是先判斷插入的非聚集索引頁是否在緩衝池中。如果在,則直接插入;如果不在,則先放入一個插入緩衝區中,好似欺騙數據庫這個非聚集的索引已經插到葉子節點了,然後再以一定的頻率執行插入緩衝和非聚集索引頁子節點的合併操作,這時通常能將多個插入合併到一個操作中(因爲在一個索引頁中),這就大大提高了對非聚集索引執行插入和修改操作的性能。

插入緩衝的使用需要滿足以下兩個條件:

索引是輔助索引。

索引不是唯一的。

當滿足以上兩個條件時,InnoDB存儲引擎會使用插入緩衝,這樣就能提高性能了。不過考慮一種情況,應用程序執行大量的插入和更新操作,這些操作都涉及了不唯一的非聚集索引,如果在這個過程中數據庫發生了宕機,這時候會有大量的插入緩衝並沒有合併到實際的非聚集索引中。如果是這樣,恢復可能需要很長的時間,極端情況下甚至需要幾個小時來執行合併恢復操作。

輔助索引不能是唯一的,因爲在把它插入到插入緩衝時,我們並不去查找索引頁的情況。如果去查找肯定又會出現離散讀的情況,插入緩衝就失去了意義。

可以通過命令SHOW ENGINE INNODB STATUS來查看插入緩衝的信息:

  1. mysql> show engine innodb status\G;  
  2. *************************** 1. row ***************************  
  3.   Type: InnoDB  
  4.   Name:   
  5. Status:   
  6. =====================================  
  7. 100727 22:21:48 INNODB MONITOR OUTPUT 
  8. =====================================  
  9. Per second averages calculated from the last 44 seconds  
  10. ......  
  11. -------------------------------------  
  12. INSERT BUFFER AND ADAPTIVE HASH INDEX  
  13. -------------------------------------  
  14. Ibuf: size 7545, free list len 3790, seg size 11336,  
  15. 8075308 inserts, 7540969 merged recs, 2246304 merges  
  16. ......  
  17. ----------------------------  
  18. END OF INNODB MONITOR OUTPUT 
  19. ============================  
  20.  
  21. 1 row in set (0.00 sec) 

seg size顯示了當前插入緩衝的大小爲11 336*16KB,大約爲177MB,free list len代表了空閒列表的長度,size代表了已經合併記錄頁的數量。下面一行可能是我們真正關心的,因爲它顯示了提高性能了。Inserts代表插入的記錄數,merged recs代表合併的頁的數量,merges代表合併的次數。merges∶merged recs大約爲3∶1,代表插入緩衝將對於非聚集索引頁的IO請求大約降低了3倍。

目前插入緩衝存在一個問題是,在寫密集的情況下,插入緩衝會佔用過多的緩衝池內存,默認情況下最大可以佔用1/2的緩衝池內存。以下是InnoDB存儲引擎源代碼中對insert buffer的初始化操作:

  1. /** Buffer pool size per the maximum insert buffer size */  
  2. #define IBUF_POOL_SIZE_PER_MAX_SIZE 2  
  3. ibuf->max_size = buf_pool_get_curr_size() / UNIV_PAGE_SIZE  
  4.           / IBUF_POOL_SIZE_PER_MAX_SIZE; 

這對其他的操作可能會帶來一定的影響。Percona已發佈一些patch來修正插入緩衝佔用太多緩衝池內存的問題,具體的可以到http://www.percona.com/percona-lab.html查找。簡單來說,修改IBUF_POOL_SIZE_PER_MAX_SIZE就可以對插入緩衝的大小進行控制,例如,將IBUF_POOL_SIZE_PER_MAX_SIZE改爲3,則最大隻能使用1/3的緩衝池內存。

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