master thread的縣城優先級別最高.其內部由幾個循環(loop)組成:主循環(loop)、後臺循環(background loop)、刷新循環(flush loop)、暫停循環(suspend loop)。master thread 會根據數-據庫運行的狀態在loop,background loop、flush loop 和suspend loop 中進行切換.
每秒一次的操做:
一、日誌緩衝刷新到磁盤,即便這個事務尚未提交(老是).
二、合併插入緩衝(可能)
三、至多刷新100個InnoDB的緩衝池中的髒頁到磁盤(可能)。
四、若是當前沒有用戶活動,切換到background loop(可能).
即便某個事務尚未提交,innodb存儲引擎仍然會每秒將重作日誌緩衝中的內容刷新到重作日誌文件.這一點是必須知道的,這能夠很好地解釋爲何再大的事務commit的時間也是很快的。
合併插入緩衝(insert buffer) 並非每秒都發生。Innodb存儲引擎會判斷當前一秒內發生的IO次數是否小於5次,若是小於5次,innodb 認爲當前的IO壓力很小,能夠執行合併插入緩衝的操做.
一樣,刷新100個髒頁也不是每秒都在發生。innodb存儲引擎經過判斷當前緩衝池中髒頁的比例(buf_get_modified_ratio_pct)是否超過配置文件中innodb_max_dirty_pages_pct這個參數(默認爲90,表明%90)若是超過了這個閥值,Innodb存儲引擎認爲須要作磁盤同步操做,將100個髒頁寫入磁盤.
Innodb存儲引擎每10秒的操做
一、刷新100個髒頁到磁盤(可能)
二、合併至多5個插入緩衝(老是)
三、將日誌緩衝刷新到磁盤(老是)
四、刪除無用的Undo頁(老是)
五、刷新100個或者10個髒頁到磁盤(老是)
在以上的過程當中,innodb存儲引擎會先判斷過去10秒以內磁盤的IO操做是否小於200次。若是是,innodb存儲引擎認爲當前有足夠的磁盤IO操做能力.所以將100個髒頁刷新到磁盤。接着,Innodb 存儲引擎會合並插入緩衝。不一樣於每1秒操做時可能發生的合併插入緩衝操做,此次的合併插入緩衝操做總會在這個階段進行。以後Innodb存儲引擎會執行一次將日誌緩衝刷新到磁盤的操做,這與每秒發生的操做是同樣的。
接着InnoDB存儲引擎會執行一步full purge操做,即刪除無用的Undo頁。對錶執行update、delete這類的操做時,原先的行被標記爲刪除,可是由於一致性讀(consistent read)的關係,須要保留這些版本的信息。可是在full perge 過程當中,Innodb存儲引擎會判斷當前事務系統中已刪除的行是否能夠刪除,好比有時候可能還有查詢操做須要讀取以前版本undo信息,若是能夠,innodb會當即將其刪除.從源代碼中能夠發現,innodb存儲引擎在操做full purge的時,每次最多刪除20個undo頁.
而後,Innodb存儲引擎會判斷緩衝池中髒頁的比例(buf_get_modified_ratio_pct),若是有超過70%的髒頁,則只需刷新10%的髒頁到磁盤。
最後,Innodb存儲引擎會產生一個檢查點(checkpoint),innodb存儲引擎的檢查點也成爲模糊檢查點(fuzzy checkpoint)。Innodb存儲引擎在checkpoint時並不會把全部緩衝池中的髒頁都寫入磁盤,由於這樣可能對性能產生影響,而只是將最老日誌序列號(oldest LSN)的頁寫入磁盤.
接着來看background loop,若當前沒有用戶活動(數據庫空閒時)或者數據庫關閉時,就會切換到這個循環。這個循環會執行如下操做:
一、刪除無用的Undo頁(老是)
二、合併20個插入緩衝(老是)
三、跳回到主循環(老是)
四、不斷刷新100個頁,直到符合條件(可能,跳轉到flush loop中完成)
若是flush llop中也沒有事情能夠作了,innodb存儲引擎會切換到suspend_loop,將master thread掛起,等待事件的發生,若啓用了Innodb存儲引擎.卻沒有使用任何Innodb存儲引擎的表,那麼master thread老是處於掛起狀態.
從Innodb plugin 開始,用show engine innodb status 能夠查看當前master thread的狀態信息,以下所示:這裏能夠看到主循環執行了 6300568;node
mysql> show engine innodb status\G; *************************** 1. row *************************** Type: InnoDB Name: Status: ===================================== 2015-02-13 13:42:44 2ac95fdf3940 INNODB MONITOR OUTPUT ===================================== Per second averages calculated from the last 14 seconds ----------------- BACKGROUND THREAD ----------------- srv_master_thread loops: 6300568 srv_active, 0 srv_shutdown, 5298516 srv_idle srv_master_thread log flush and writes: 11599055
日均月異隨着市場上磁盤設備愈來愈先進;IO讀寫愈加的高了起來...innodb存儲引擎若是安裝之前的方式:(1秒內處理100個頁的寫入和20個插入緩衝合併;未免過於遲緩了)因此Innodb存儲引擎開始提供一個參數;用來表示磁盤IO的吞吐量,參數爲Innodb_io_capacity,默認值爲200.對於刷新到磁盤的數量,會按照Innodb_io_capacity的百分比來刷新相對數量的頁。規則以下:
一、在合併插入緩衝時,合併插入緩衝的數量爲Innodb_io_capacity數值5%
二、在從緩衝區刷新髒頁時,刷新髒頁的數量爲innodb_io_capacity。
另一個問題是參數innodb_max_dirty_pages_pct的默認值,在mysql5.1版本以前(包括5.1),該值得默認值爲90,意味着髒頁佔緩衝池的90%。目前該值默認是75%;
另一個參數是innodb_adaptive_flushing(自適應地刷新),該值影響每1秒刷新髒頁的數量。原來的刷新規則是:若是髒頁在緩衝池所佔的比例小於innodb_max_dirty_pages_pct時,不刷新髒頁;大於Innodb_max_dirty_pages_pct時,刷新100個髒頁,而innodb_adaptive_flushting參數的引入,innodb存儲引擎會經過一個名爲buf_flush_get_desired_flush_rate的函數來判斷須要刷新髒頁最合適的數量。而buf_flush_get_desired_flush_rate是經過判斷產生重作日誌的速度來判斷最合適的刷新髒頁的數量。所以當髒頁的比例小於Innodb_max_dirty_pages_pct時,也會刷新必定量的髒頁。
關鍵性
Innodb存儲引擎的關鍵性特性包括插入緩衝、兩次寫(double wirte)、自適應哈希索引(adaptive hash index)。
插入緩衝
插入緩衝是Innodb存儲引擎關鍵特性;Insert Buffer和數據頁同樣,也是物理頁的一個組成部分;
彙集索引通常是順序的,不須要磁盤的隨機讀取,
在不少狀況下,一張表有多個非彙集的輔助索引(secondary index)
InnoDB存儲引擎開創性設計了插入緩衝,對於非彙集索引的插入或更新操做,不是每一次直接插入索引頁中。而是先判斷插入的非彙集索引頁是否在緩衝池中。若是在,則直接插入;若是不在,則先放入一個插入緩衝區中,好似欺騙數據庫這個非彙集索引已經查到葉子節點了.而後再以必定的頻率執行插入緩衝和非彙集索引頁子節點的合併操做,這時一般能將多個插入合併到一個操做中(由於在一個索引頁中),這就大大提升了對非彙集索引執行插入和修改操做的性能。
插入緩衝的使用須要知足如下兩個條件:
一、索引是輔助索引。
二、索引不是惟一的。
輔助索引不能是惟一的,由於在把它插入到插入緩衝時,咱們並不去查找索引頁的狀況。若是查找確定會出現離散讀的狀況,插入緩衝就失去了意義.
Ibuf: size 1, free list len 0, seg size 2, 38 merges
seg size顯示當前插入緩衝的大小爲2*16KB
free list len 0
free list len 表明了空閒列表的長度。
目前插入緩衝存在一個問題是,在寫密集的狀況下,插入緩衝會佔用過多的緩衝池內存,默認狀況下最大可佔用1/2的緩衝池內存。
修改IBUF_POOL_SIZE_PER_MAX_SIZE就能夠對插入緩衝的大小進行控制;列如;將IBUF_POOL_SIZE_PER_MAX_SIZE改成3,則最大隻能使用1/3的緩衝池內存.
兩次寫
若是說插入緩衝帶給Innodb存儲引擎的是性能,那麼兩次寫帶給Innodb存儲引擎的數據的可靠性,當數據庫戎機時,可能發生數據庫正在寫一個頁面,而這個頁只能寫一部分(好比16K的頁,只寫前4K的頁)的狀況,咱們稱之爲部分寫失效(partial page write);
注意:重作日誌中記錄的是對物理操做,如偏移量800,寫'aaa'記錄。若是這個頁自己已經損壞了,再對其進行重作是沒有意義的。這就是說,在應用(apply)重作日誌以前,咱們須要一個頁的副本,當寫入失效發生時,先經過頁的副原本還原該頁,再進行重作,這就是doublewrite.innodb存儲引擎doublewerite;
doublewrite由兩部分組成:一部分是內存中的doublewrite buffer,大小爲2MB;另外一部分是物理磁盤上共享表空間中連續的128個頁;即兩個區(extent),大小一樣爲2MB;當緩衝池的髒頁刷新時,並不直接寫磁盤,而是會經過memcpy函數將髒頁先拷貝到內存中的doublewrite buffer,以後經過doublewrite再分兩次,每次寫入1MB到共享表空間的物理磁盤上,而後立刻調用fsync函數 ,同步磁盤,避免緩衝寫帶來的問題。在這個過程當中,由於doublewrite頁是連續的,所以這個過程是順序寫的.開銷並非很大。在完成doublewrite頁的寫入後,再將doublewrite buffer中的頁寫入各個表空間文件中,此時的寫入則是離散的。能夠經過如下命令觀察double write運行情況;mysql
mysql> show global status like 'innodb_dblwr%'\G; *************************** 1. row *************************** Variable_name: Innodb_dblwr_pages_written Value: 10005304 *************************** 2. row *************************** Variable_name: Innodb_dblwr_writes Value: 3272391 2 rows in set (0.01 sec)
能夠看到,doublewrite 一共寫了10005304個頁,但實際的寫入次數爲3272391,若是你發現你的系統在高峯時Innodb_dblwr_pages_written:Innodb_dblwr_writes遠小於64:1,那麼說明你的系統寫入壓力並非很高.
若是操做系統在將頁寫入磁盤的過程當中崩潰了,在恢復過程當中,Innodb存儲引擎能夠從共享表中的doublewrite找到改頁的一個副本,將其拷貝到表空間文件,再應用重作日誌。
參數skip_innodb_doublewrite能夠禁止使用兩次寫功能,這時可能會發生前面說起的寫失效問題。
注意:有些文件系統自己就提供了部分寫失效的防範機制,如ZFS文件系統。在這種狀況下,咱們就不要啓用doublewrite了。
自適應哈希索引
哈希(hash)是一種很是快的查找方法,通常狀況下查找時間複雜度爲o(1)。經常使用於join操做,如SQL Server 和Oracle中的哈希鏈接(hash join)。可是SQL Server和Oracle等常見的數據庫並不支持哈希索引(hash index)。MySQL的Heap存儲引擎默認的索引類型爲哈希,而Innodb存儲引擎提出了另一種實現方法,自適應hash index(adaptive hash index)。
Innodb存儲引擎會監控對錶上索引的查找,若是觀察到創建哈希索引能夠帶來速度的提高,則創建hash index,因此稱之爲自適應(adaptive)的。自適應哈希索引經過緩衝池的B+tree構造而來,所以創建的速度很快.
Hash table size 9461399, node heap has 2933 buffer(s)
7767.23 hash searches/s, 130.87 non-hash searches/s
這裏主要輸出的信息有:包括自適應哈希索引的大小、使用狀況、每秒使用自適應hash index搜索的狀況。值得注意的是,hash索引只能用來搜索等值的查詢,如select * from table where index_col = 'xxx' 而對其餘查找的類型,如範圍查找,是不能使用的。所以這裏出現了non-hash searches/s的狀況。用hash searches:non-hash searches命令能夠大概瞭解使用哈希索引後的效率.
咱們能夠經過參數innodb_adaptive_hash_index來禁用或啓動此特性,默認爲開啓。
sql
注意:mysql一條查詢語句只能運行在一顆/一核CPU上;因此一條複雜的查詢語句;不如多條簡單查詢語句性能好;數據庫