MySQL深入學習(2)——InnoDB存儲引擎

1. InnoDB存儲引擎體系架構

     innoDB的存儲引擎主要體系結構如上圖所示

    首先是工作線程:默認7個後臺線程,分別是4個io thread(insert buffer、log、read、write),1個master thread(優先級最高),1個鎖(lock)監控線程,1個錯誤監控線程。可以通過show engine innodb status來查看。新版本已對默認的read thread和write thread分別增大到4個,可通過show variables like 'innodb_io_thread%'查看。

    每個線程操作的同一個塊大內存池:該內存池中會被分爲多個區域,分別是緩衝池(buffer pool)、重做日誌緩衝池(redo log buffer)以及額外的內存池(additional memory pool)。內存池所負責也就是維護線程需要訪問的數據結構、緩存磁盤文件的數據,方便快速讀取,同時在對磁盤文件的數據修改之前在這裏緩存,以及重做日誌緩存等。具體配置可由show variables like 'innodb_buffer_pool_size'show variables like 'innodb_log_buffer_size'show variables like 'innodb_additional_mem_pool_size'三條指令查看來查看。

  第三部分則是最基礎的InnoDB存儲引擎對應的數據庫表磁盤文件、日誌文件。

2. InnoDB存儲引擎的工作線程 

2.1 Master Thread

    該線程是InnoDB的核心後臺線程,大部分工作都在這裏完成,負責將緩衝池中的數據異步刷新到磁盤,保證數據的一致性,包括髒頁的刷新、合併插入緩衝、undo頁的回收等。

    Master Thread具有最高的線程優先級別,其內部有多個循環組成,包括主循環(Loop)、後臺循環(background loop)、刷新循環(flush loop)以及暫停循環(suspend loop)。主線程會依據數據庫運行狀態在四個循環中切換。

    1. 主循環Loop

    主循環包括了大多數操作,其中主要分爲兩部分,分別是每秒進行的操作和每10秒進行的操作。僞代碼如下

可以看到,在loop循環內,首先是一個for循環,該循環總共爲10次,其中通過線程的sleep方法實現所謂的每秒和每10秒執行一次的操作,這種方式肯定是不精確地,肯定會有延遲現象,最多也就是大概維持在這個頻率。

for循環內的操作(也就是每秒一次的操作)包括:

(1)日誌緩衝刷新到磁盤(即使事務沒有提交,一定會發生)

(2)合併插入緩衝(不一定)

(3)至多刷新100個InnoDB緩衝池中的髒頁到磁盤(可能發生)

(4)判斷當前是否有用戶活動,如果沒有則切換到後臺循環執行。

for循環外的操作(每10秒一次執行的操作)包括:

(1)刷新100個髒頁的數據到磁盤文件中(可能)

(2)合併至多5個插入緩衝(一定)

(3)將日誌緩衝刷新到磁盤中(一定)

(4)刪除無用的undo頁(一定)

(5)刷新100個或者10個髒頁到磁盤文件中(一定)

    2. 後臺循環(background)

    若當前沒有用戶活動,也就是沒有客戶端連接或者用戶登陸時,就會切換到這個循環,主要執行操作如下:

(1)刪除無用的undo頁(一定)

(2)合併20個插入緩衝(一定)
(3)跳回到主循環(一定)

(4)不斷刷新100個頁知道符合條件(可能,跳轉到flush loop中完成)
如果flush loop中也沒有什麼事情可做了,InnoDB就會切換到suspend loop中,將主線程掛起,等待時間的發生,如果用戶啓用了InnoDB引擎,卻沒有任何基於InnoDB的數據庫表,那麼主線程將總是處於掛起狀態。

2.2 IO Thread

    在MySQL中,InnoDB使用了大量的AIO來處理寫IO請求,這樣可以很大的提高數據庫性能,而IO Thread的任務就是負責處理這些IO請求的回調(AIO基於回調來實現異步加非阻塞),主要有四類IO Thread,分別是write、read、insert buffer和log。可通過innodb_read_io_threads和innodb_write_io_threads參數設置。

2.3 Purge Thread

    事務被提交後,其所使用的undolog可能不再需要,因此需要purge Thread來回收已經使用並分配的undo頁,該線程只能存在1個,在innoDB1.1版本之前原本該線程的任務是放在主線程中執行的,但是從1.1版本開始,purge操作有獨立線程執行完成。

 

3. InnoDB引擎的內存結構

3.1 緩衝池buffer pool

    緩衝池,實際上就是一塊內存區域,由於磁盤的讀寫性能相較於CPU的處理速度來說相差較大,所以會通過內存(緩衝池)來提高數據庫的整體性能,數據庫中讀取頁中的的數據時,會首先將數據讀取到緩衝池中,下次再讀取這個頁中的數據時,就會直接從緩衝池中獲取,如果緩衝池中沒有這部分數據,那麼就去讀取磁盤數據文件,緩存到緩衝池中;對於數據庫中頁的修改操作,首先是修改在緩衝池中的頁,然後再以一定的頻率將數據同步更新到磁盤上。

    緩衝池中緩存的數據主要包括:索引頁、數據頁、undo頁、插入緩衝、自適應哈希索引、InnoDB存儲的鎖信息、數據字典信息等。其中的索引頁和數據頁佔據較大部分。

    緩衝池允許有多個實例,每個頁根據哈希值平均分配到不同的緩衝池實例中,這樣做的好處是減少數據庫內部的資源競爭,增加數據庫的併發處理量。可以通過innodb_buffer_pool_instances來查看和配置,該值默認爲1,還可以通過innodb_buffer_pool_stats表來查詢各個緩衝池的狀態。

    LRU List、Free List和Flush List

    緩衝池是一個很大的內存區域,其中存放各種類型頁的數據,但是,內存區域是有限的,通常來說,我們不可能把所有的磁盤數據文件全部緩存到內存中,而是通過各種策略來管理內存中的數據。數據庫緩衝池是通過LRU(最近最少使用)算法來進行管理的,在innoDB引擎中,緩衝池中頁的大小默認爲16kb,同樣使用LRU算法對緩衝池進行管理,但對LRU算法進行了一些修改優化。

   在innoDB的存儲引擎中,LRU列表中還加入了midpoint位置,新讀取到得頁,雖然是最新讀取的數據,但不會放在LRU隊列最前端,而是會放在midpoint的位置,默認配置下,midpoint被設置爲隊列長度的5/8處,但可以通過innodb_old_blocks_pct控制。在midpoint之後的的隊列元素就是old隊列,之前的就是new隊列。

    之所以採用midpoint,而不是直接放在隊列首部,是因爲某些SQL操作可能會使緩衝池中的熱點數據被擠出去,常見的這類操作爲索引或者數據的掃描操作,這類操作會訪問表中的許多頁,甚至是全部的頁,而這些頁又僅僅只是本次操作中需要訪問操作的,並不能算是熱點數據,但終歸還是要掃描到緩衝區中的,如果放在緩衝區隊列首部,那麼就可能會把大量的真正熱點數據擠出去,導致這些熱點數據在下次讀取時又需要從磁盤中重新讀取,嚴重影響性能。

    所以,innoDB用了兩個參數來解決上面這個問題,除了midpoint外,還有另一個innodb_old_blocks_time,用於表示頁讀取到mid位置後需要多久才加入到LRU隊列的熱點數據端。因此當執行上述所說的SQL操作時,可以通過下面的方法儘可能使LRU列表中的熱點數據不被刷出。

    首先,新讀取的數據肯定會被放在mid位置上,如果該數據在mid位置之後(也就是old部分)存活的次數超過innodb_old_blocks_time次,那麼該數據就會放在new隊列端(這個操作就是Pages made young),而如果因爲innodb_old_blocks_time參數的設置導致頁數據並沒有從old移動到new隊列,該操作被稱爲Pages not  made young,這樣就可以保證mid位置的前面作爲熱點數據儘量保持其存活,而非熱點數據就會處於mid位置的後面,快速被淘汰。   

    通過show engine innodb status命令可以查看內存使用情況(該命令顯示的肯定不是實時狀態,而是過去的某個時間範圍內的狀態,比如前60秒內的狀態):

    其中,Total large memory表示分配的最大內存空間,Buffer pool size就表示當前共有多少個頁的數據,大小爲512*16kb,而Free buffers表示Free 隊列中頁的數量,Database pages 表示LRU隊列中頁的數量。可能會存在Free buffers+Database pages不等於Buffer pool size,因爲Buffer pool size中可能還會有自適應哈希索引、Lock信息等數據,這些數據不用LRU算法維護,因此不會存在於LRU隊列中。

    Pages made young 0, not young 0:記錄了LRU列表中頁移動到new端的次數。

    0.00 youngs/s, 0.00 non-youngs/s:表示每秒這兩類操作發生的次數。

    還有另一個非常重要的觀察參數buffer pool hit rate,該參數表示緩存命中率,如果命中率爲100%,則表示該緩衝池非常優秀,如果小於95%,那麼就必須檢查是否是由於全表掃描引起的LRU列表被污染的問題。

關於unzip_LRU

   在上圖中的數據中,我們可以看到倒數第二行兩個參數LRU len:256,unzip_LRU len:0,這兩個參數分別表示由LRU管理的總頁數,而在innoDB引擎從1.0版本之後支持壓縮頁的功能,會將原本16kb的頁壓縮爲1kb、2kb、4kb和8kb,而這部分壓縮後的頁則是由unzip_LRU進行管理的,但是LRU len的數量是包含unzip_LRU的數量的。

關於Flush List

    當LRU中的某個頁的數據被修改後,那麼該頁就被稱爲髒頁,即緩衝池中該頁的數據與磁盤上頁的數據不一致,而這部分髒頁就會複製一份於Flush List中,這時數據庫會通過checkpoint機制將髒頁的數據刷新到磁盤上,也就是說LRU List中和Flush LIst中各有一份髒頁,LRU中保證該頁的緩衝可用性,而Flush List則是用來講髒頁數據刷新到磁盤,兩者互不影響。在上圖的Modified db pages數據就是髒頁的數量。

在innodb中定義三種page(頁):

1) free page :此page未被使用(通常都是數據庫剛剛啓動的時候),此種類型page位於free List中,一旦某個頁的數據被讀取或者操作,那麼該頁就會從free List中移除,移動到LRU List中

2) clean page:此page被使用,對應數據文件中的一個頁面,但是頁面沒有被修改(僅做讀取操作),此種類型 page位於lru List中

3) dirty page:此page被使用,對應數據文件中的一個頁面,但是頁中的數據被修改過,此種類型page位於lru List和flush List中

 

3.2 重做日誌緩衝(redo log buffer)

    重做日誌緩衝,或者說日誌緩衝,innoDB引擎首先將重做日誌信息存放到這個緩衝區中,然後將按一定頻率區刷新到重做日誌文件中,重做日誌緩衝區一般不需要設置到很大,因爲一般都會每秒刷新一次日誌緩衝區數據到日誌文件中,因此只需要保證每秒產生的事務量在這個緩衝大小之內即可。該值由參數innodb_log_buffer_size控制,默認爲8mb。

 

4. Checkpoint機制

    在上面的Flush List中說到了,在關於髒頁數據刷新(寫回)到磁盤中時,是通過Checkpoint機制實現。什麼是checkpoint機制?可以先看看下面的問題,就可以知道什麼是checkpoint機制。

    上面已經說過,緩衝區的目的就是爲了降低CPU處理速度與磁盤IO速度的差距,因此對於數據頁的操作都是現在緩衝區中完成,如果該頁中的數據發生了改變,那麼這個緩衝區中的頁就變成了髒頁,因爲其與磁盤數據是不一致的,所以就需要將緩衝區最新的數據頁刷新到磁盤中。

    (1)第一個問題來了,如果每次緩衝區的一個數據頁發生了改變,就要刷新一次數據到磁盤上,那麼這個開銷將是非常可怕的,而且一旦在刷新到磁盤的過程中數據庫宕機,那麼這部分數據就無法恢復。

    對於這個問題,現在的支持事務機制的數據庫普遍採用了write and log策略,也就是當事務提交時,先寫重做日誌,在修改頁,即使數據庫突然宕機也可以通過重做日誌來進行數據恢復。

   做一個假設,如果我們的緩衝區和磁盤空間可以無限大,我們可以將數據庫中所有的數據全部緩存到緩衝區中,而且日誌文件可以無限呢增長,那麼從某種程度上來說卻是可以不需要數據髒頁回寫磁盤這個步驟了。但是,這種假設目前來說肯定是不可能的,現在一個大型系統的數據庫基本都會有上TB的數據,但是內存TB級別的有幾個見過?其次,磁盤空降某種程度上來說,卻是可以做到無限增長,但是,增長是沒問題,但是在進行數據恢復或者重啓數據庫的時候,那一定是崩潰的,如果日誌文件達到幾TB,估計恢復時長可能就得幾個月了。

   (2)所以第二個問題,如何去減小日誌文件的大小,一次減少數據庫恢復時間,以及保證緩衝區的數據能夠及時刷新到磁盤?

這個問題就是checkpoint機制所負責解決的問題了,也正是checkpoint機制的作用。

首先,如果數據庫宕機或者其他原因,需要重新啓動,那麼數據庫是不需要重做日誌文件中的所有日誌的,因爲在checkpoint之前的頁都已經刷回磁盤,所以只需要對checkpoint後的重做日誌進行恢復即可,這樣就大大縮短了恢復的時間(有點類似Redis中通過AOF日誌恢復數據的方式)。

其次,如果緩衝區空間不足,依據LRU算法也會溢出最近最少使用的數據頁,而如果該頁是髒頁,那麼就會強制執行checkpoint,將該頁數據刷回磁盤。

具體checkpoint是如何指定的,這個指定規則比較複雜,不做過多解釋,但checkpoint發生時所做的工作無非就是將緩衝池的髒頁刷新到磁盤中。比如上面介紹InnoDB的線程中,Master Thread就會進行髒頁刷新操作,但不僅僅只有Master Thread中會進行髒頁數據刷新。

 

5. InnoDB的關鍵特性

InnoDB的關鍵特性包括:

(1)插入緩衝

(2)兩次寫

(3)自適應哈希索引

(4)異步IO

(5)刷新鄰接頁

5.1 插入緩衝(Insert Buffer)

     插入緩衝這塊建議去了解一下什麼是聚集索引,什麼是非聚集索引,二者之間的區別是什麼,可以很快就理解這部分內容。不過後續講解索引時,我也會詳細說明。在《MySQL技術內幕》書中對這塊的描述個人覺得很抽象,不太懂,我結合對於非聚集索引的理解(個人吐槽一下書的內容排版,爲什麼不把頁、索引的概念和原理介紹放在前面),重新翻譯了一下關於插入緩衝這部分的內容(個人理解,可能不太正確)。

    Insert Buffer

    首先,對於聚集索引(一般來說也就是基於主鍵建立的索引)其索引和數據是存儲在一起的,而對於非聚集索引(輔助索引),其索引和數據時分開存儲的,非聚集索引頁下中並不保存數據,而是數據所在的物理存儲位置。我們在通過非聚集索引查詢數據時,依據索引所獲取到的是目標數據在磁盤中的存儲位置,然後依據這個位置前往數據頁中進行讀取。也即是說,非聚集索引是單獨的一個頁,而真正的數據在另一個數據頁中,該數據頁中是按照聚集(主鍵)索引進行存儲的。(這也是爲什麼書中說插入緩衝也是物理頁的一部分,實際上就是指的是非聚集索引頁)

    前面也說過了,爲了提高性能,降低CPU處理速度與磁盤IO速度之間的差距,引入了緩衝區。緩衝區會加載物理磁盤頁中的數據到內存中,其中就包括非聚集索引頁,和數據頁緩衝作用一樣,如果非聚集索引的數據發生了改變(插入或更新)並不是直接寫入到物理磁盤頁中,而是先寫入到緩衝區中,然後以一定的頻率將非聚集索引數據刷新到磁盤中,這樣就可以將多次非聚集索引的插入或者更新操作合併,提高非聚集索引插入性能,這就是插入緩衝(Insert Buffer)。

    但InnoDB引擎對於Insert Buffer的使用有兩個條件限制:1、索引必須是輔助索引,或者說是非聚集索引;2、索引不是唯一索引。

    第一個條件很容易理解爲什麼,但是第二個非唯一索引的的限制原因在於:如果是唯一索引,那麼在插入數據的時候,就必須要判斷一次插入的輔助索引字段的數據內容是否唯一,就必須要進行一次查找,也就意味着要進行一次離散讀取(或者說隨機讀取,也就是上面所說的從非聚集索引中取到數據頁的存儲位置進行讀取),這也就失去了Insert Buffer的意義了。

    同樣的,可以通過命令行命令show engine innodb status來查看insert buffer緩衝區的情況。

    Change Buffer

    如果說上面的Insert Buffer只是針對插入緩衝,那麼在InnoDB1.0版本之後引入了Change Buffer,可以將其視爲Insert Buffer的升級版,可以支持DML操作(插入、刪除、修改)都進行緩衝,分別是Insert Buffer、Delete Buffer和Purge Buffer。

    但Change Buffer的應用也會造成一些問題,如果說對於存在非聚集索引的表進行大量的DML數據操作,那麼肯定會導致插入緩衝佔用大量的緩衝區空間,進而對其他的數據操作產生影響。可以通過innodb_change_buffer_max_size來設置插入緩衝允許佔用總緩衝區最大多少百分比的空間,取值範圍0到50。

    Insert Buffer的內部實現

    Insert Buffer的數據結構是一顆B+樹,而且整個InnoDB使用一顆B+樹來維護Insert  Buffer。Insert Buffer會將輔助索引記錄緩存起來,當緩存記錄過多時,就會將記錄合併回頁,然後經行插入操作。這就需要一個空間來記錄各個輔助索引頁的剩餘空間。
在InnoDB中,存在一個Insert Buffer bitmap頁,一個Insert Buffer bitmap管理16384個頁(256個區),每一個輔助索引頁在Insert Buffer bitmap頁中佔據4位空間。


剩餘空間用兩位表示

0:表示無可用空間
1:表示剩餘空間大於1/32頁
2:表示剩餘空間大於1/16頁
3:表示剩餘空間大於1/8頁
當剩餘空間小於1/32時,就會主動經行 Merge Insert Buffer 操作,這一步會在Master Thread線程中經行。
Insert Buffer的數據結構是一顆B+樹,其中非葉子節點存放的是search key(鍵值),其的構成


space爲表空間id;marker用來兼容老版本;offset表示頁所在偏移量
葉子節點構成


其中,metadata 記錄的每一列的類型,長度;secondary index record 記錄的具體值,數據插入流程如下
1.一個輔助索引插入到頁(space,offset)
2.檢查這個頁是否在緩衝池中
在:直接插入
不在:繼續
3.構造一個search key
4.查詢insert buffer樹
5.生成邏輯記錄並插入樹中

5.2 兩次寫(doublewrite)

    如果說Insert Buffer帶給InnoDB存儲引擎的是性能的提升,那麼doublewrite帶給InnoDB存儲引擎的是數據的可靠性。

    由於innodb page是16K,一般系統page是4k,當有個update語句需要對業內記錄加1,當第一個4k中記錄加1後,系統宕機,重啓恢復時候,innodb 不知道從哪裏給記錄加1,如果給16k裏所有記錄都加1,就會導致第一個4k裏面記錄加2,必然導致數據不一致,這種情況就是部分寫失效double write buffer就解決了這個問題。但前面說過,InnoDB還有一個重做日誌不是可以還原恢復數據嗎?不能恢復數據的原因如下

    因爲Innodb中的日誌是邏輯的,所謂邏輯就是比如插入一條記錄時,它可能會在某一個頁面(這條記錄最終被插入的位置)的多個偏移位置寫入某個長度的值,例如頁頭的記錄數、槽數、頁尾槽數據、頁中的記錄值等。這些本是一些物理操作,而Innodb爲了節省日誌量及其它原因,設計爲邏輯處理的方式,即在一個頁面上插入一條記錄時,對應的日誌內容包括表空間號、頁面號、將被記錄的各個列的值等內容,在真正物理插入的時候,纔會將日誌邏輯操作轉換爲前面的物理操作。

先有邏輯日誌,再有物理操作,但是這樣需要有一個前提,就是物理操作的頁面是正確的。如果那個數據頁本身是錯誤的,這種錯誤可能是上次的操作導致的寫斷裂(1個頁面爲16KB,分多次寫入,後面的可能沒有寫成功,導致這個頁面不完整)或者其它原因,那麼這個邏輯操作就沒辦法完成了。因爲如果這個頁面不正確的話,裏面的數據是無效的,就可能會產生各種不可預料的問題。

因此首先要保證這個頁面是正確的,方法就是兩次寫。double write的流程如下

    

double write由兩部分組成,一部分是InnoDB內存中的double write buffer,大小爲2M,另一部分是物理磁盤上ibdata系統表空間中大小爲2MB,共128個連續的Page,既2個分區。其中120個用於批量寫髒,另外8個用於Single Page Flush。做區分的原因是批量刷髒是後臺線程做的,不影響前臺線程。而Single page flush是用戶線程發起的,需要儘快的刷髒並替換出一個空閒頁出來。

在對緩衝池的髒頁進行刷新時,並不直接寫磁盤,而是會通過 memcpy函數將髒頁先複製到內存中的 doublewrite buffer,之後通過 doublewrite buffer再分兩次,每次1MB順序地寫入共享表空間的物理磁盤上,然後馬上調用 fsync函數,同步磁盤,避免緩衝寫帶來的問題。在這個過程中,因爲 doublewrite頁是連續的,因此這個過程是順序寫的,開銷並不是很大。在完成 doublewrite頁的寫入後,再將 doublewrite buffer中的頁寫入各個表空間文件中,此時的寫入則是離散的。

說白了,double write就是在寫數據頁之前,先把這個數據頁寫到一塊獨立的物理文件位置(ibdata),然後再寫到數據頁。這樣在宕機重啓時,如果出現數據頁損壞,那麼在應用redo log之前,需要通過該頁的副本來還原該頁,然後再進行redo log重做,這就是double write。

在數據庫啓動時(異常關閉的情況下),都會做數據庫恢復(redo)操作,恢復的過程中,數據庫都會檢查頁面是不是合法(校驗等等),如果發現一個頁面校驗結果不一致,則此時會用到兩次寫這個功能,這個特點也正是爲了處理這樣的錯誤而設計的。此時的操作很明白了,將兩次寫的2個BLOCK都讀出來,然後將所有這些頁面寫回到對應的頁面中去,那麼這時可以保證這些頁面是正確的,並且是在寫入前已經更新過的(最新數據)。在寫回對應頁面中去之後,那麼就可以在這基礎上繼續做數據庫恢復了,之後則不會再遇到這樣的問題了,因爲已經將最後有可能產生寫斷裂的數據頁面都恢復了。redo流程如下

MySQL InnoDB特性:兩次寫(Double Write)

    那假如在將髒頁數據刷新到Double Write Buffer中或者是從Double Write Buffer刷新到磁盤double write塊中時,發生異常導致失敗會怎麼樣呢?其實這個問題已經說過了,如果不使用double write機制,直接將緩衝區的髒頁數據刷新到磁盤中,如果1個16kb的頁在刷新過程中數據庫宕機會導致磁盤上該頁的數據結構發生異常,該頁會失效,所以導致無法通過重做日誌恢復數據,但是我們現在有了double write塊來備份一份髒頁,即使在這個備份的過程中異常宕機導致double write塊的頁異常,在通過重做日誌進行數據恢復時是不影響的,因爲我們只考慮的是數據頁的合法性,而不考慮double write塊中數據頁的合法性。

5.3 自適應哈希索引

    哈希是一種非常快速的查找方法,在一般情況下這種查找的時間複雜度爲O(1),而B+樹的查找次數取決於樹的高度。InnoDB會監控對錶上各索引頁的查詢,如果觀察到建立哈希索引可以提升查詢速度,則自動建立哈希索引,這就是自適應哈希索引(AHI)。

   AHI通過對緩衝池的B+樹頁構造而來,因此建立的速度很快,而且不會對整張表構建哈希索引,而是會依據訪問的頻率和模式來自動的爲某些熱點數據頁建立哈希索引,當然,哈希索引的建立還需要一些條件:

(1)對於頁數據的連續查詢模式相同:也就是where後的條件語句格式相同(條件值不用相同),而且必須是等於判斷的條件語句,比如

where  name = 'xxx' 或者是 where  name = 'xxx' and age = 11

(2)同一個查詢模式,必須連續查詢次數大於100次,或者頁中的數據被連續訪問了至少N次,其中N=頁中記錄數量/16。

5.4 異步IO(AIO)

實際上就是指在進行磁盤操作時採用AIO進行,至於什麼是AIO可以自行了解一下,在進行磁盤IO時我們完全不需要等待其完成後再進行其他操作,比如說掃描一個磁盤上的頁數據到緩衝池中,只需要發出一條磁盤掃描也就是IO請求即可,發出之後我們可以立即執行下次IO操作,不需要等待上一個IO操作的完成。這樣就可以大大提升IO性能,充分利用CPU資源,

當然,AIO的實現是需要操作系統支持的,Windows和Linux都對AIO進行了實現,但Mac並沒有。

5.5 刷新鄰接頁

刷新鄰接頁實際上指的就是在將髒頁數據刷新回磁盤時,會檢查該頁所在區中是否還包含髒頁,如果包含,那麼就會將整個區的頁一起刷新回磁盤中,這樣的好處是顯而易見的,可以將多個IO操作合併爲一個。但也會有兩個問題產生:

(1)是否會有一些不太髒的數據頁被刷新到磁盤,而且該數據頁又很快變成了髒頁。

(2)對於現在的一些高速讀寫(高IOPS)的固態硬盤,該特性實際上是否需要?

因此,在innodb1.2版本之後,對於刷新鄰接頁屬性可以選擇是否關閉。通過設置innodb_flush_neighbors控制是否開啓此特性。

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