MySQL InnoDB儲存引擎

DB哥發表於2024-05-25

介紹

 本篇文章是對Innodb儲存引擎的概念進行一個整體的概括,innodb儲存引擎的概念是mysql資料庫中最關鍵的幾個概念之一,涉及的內容非常的廣;由於個人的理解能力有限如果有不對的地方還見諒。

 

 

 

MySQL對應InnoDB版本

MySQL 5.1》InnoDB 1.0.X

MySQL 5.5》InnoDB 1.1.X

MySQL 5.6》InnoDB 1.2.X

後臺執行緒

1.Master Thread

負責將緩衝池中的資料非同步重新整理到磁碟,保證資料的一致性;包括重新整理髒頁、合併插入緩衝、undo頁的回收。

2.IO Thread

innodb儲存引擎中大量使用了AIO(Async IO)來處理寫IO請求來提高資料庫的併發效能,共有四類IO執行緒,分別是:insert buffer thread、log thread、read thread、write thread。其中read thread和write thread分別有四個執行緒,可以通過innodb_read_io_threads和innodb_write_io_threads來配置。

SHOW VARIABLES LIKE 'innodb_%io_threads'
或者
SHOW ENGINE INNODB STATUS \G;

3.Purge Thread執行緒

purge Thread執行緒用來回收事務提交後其被分配的undo頁,預設是開啟的,可以通過innodb_purge_threads=1配置多個Purge Thread執行緒。

show variables like 'innodb_purge_threads';

配置2個Purge thread,只能修改配置檔案配置,不能線上修改
innodb_purge_threads=2

4.Page Cleaner Thread

用於多版本控制功能中回收delete和update操作產生的髒頁,用來執行將髒頁重新整理到磁碟。 

5.Binlog Dump執行緒

當配置了複製後,會在主伺服器生成一個binlog Dump執行緒來讀取二進位制修改記錄。

6.lock執行緒

      用於鎖控制和死鎖檢測

記憶體

 不要理解以為記憶體中就只有innodb buffer,還包括重做日誌緩衝、額外的記憶體池(目前還不知道比如join buffer、order buffer、key buffer、table cache buffer等是在緩衝池內部還是獨立於緩衝池在記憶體中)

1.快取池

快取的資料主要有資料頁、索引頁、重做日誌頁(undolog)、節點資訊、系統資料、插入緩衝、自適應雜湊索引、資料字典、鎖資訊等

檢視緩衝池的大小,單位位元組,轉化為MB需要/1024/1024
show variables like 'innodb_buffer_pool_size';

預設innodb有8個緩衝池,可以通過配置innodb_buffer_pool_instances
查詢
show engine innodb status \G;
或者
SELECT * FROM information_schema.innodb_buffer_pool_status;

讀操作:

   資料是以頁為儲存單位,在緩衝池中快取了很多資料頁,當第一次讀取時首先將頁從磁碟讀取到快取池中,當下一次再去讀相同的資料頁時如果該也在快取池中就直接從緩衝池中讀取而不需要再去磁碟讀,最理想的方式是將所有的磁碟資料都快取到緩衝池中但是這得記憶體足夠大才行。

修改操作

innodb儲存引擎對資料的修改也是先修改緩衝池中的資料頁(如果存在),然後根據一定的頻率重新整理到磁碟來修改資料檔案,這涉及到checkpoint機制, 

插入操作(insert buffer)

因為資料是按照聚集索引的順序排列的,所有針對聚集索引的插入一般會非常快,而非聚集索引的插入就不一定是順序的,這個時候需要離散的訪問非聚集索引頁,插入的效能往往會很差,有一種情況可能例外就是非聚集索引的時間欄位,而時間往往是順序的,這種情況會比較快,針對非聚集索引的這種情況就引入了插入緩衝。

innodb中引入了插入緩衝(insert buffer),insert buffer只針不唯一的非聚集索引,對於非聚集索引的插入和更新操作不是每次直接插入到索引檔案中,而是先判斷插入的非聚集索引頁是否存在緩衝池中,如果存在則直接插入緩衝池的非聚集索引檔案中,否則先放入到一個insert buffer物件當中,但是給人的感覺它已經插入到了索引檔案中,但是實際並沒有,然後再以一定的頻率插入到索引檔案當中,在這個過程中如果存在多個相同的索引頁的插入會合並插入,大大的提高了非聚集索引的插入效能,

因為每次插入是先插入到緩衝池當中不去查詢索引頁來判斷記錄的唯一性,因為去做判斷需要去離散查詢,所以插入緩衝不針對唯一性的非聚集索引。

在密集寫操作的情況下,插入緩衝會佔用過多的緩衝池的記憶體,預設最大可以佔到50%,原始碼中的IBUF_POOL_SIZE_PER_MAX_SIZE=2,如果將其修改為3,則最大隻能使用1/3的緩衝池的記憶體。 

 

2.LRU List、Free List、Flush List

innodb緩衝池中的頁預設大小為16KB,緩衝池通過LRU(Latest Recent Used 最新少使用)演算法來進行管理,將最頻繁的使用的頁放在LRU列表的前端,而最近少使用的頁放在尾端,當快取池中的空間不足的時會先刪除尾端的頁來釋放空間。LRU有一個midpoint位置,預設在LRU的37%的位置,左邊表示old列表,右邊表示new列表(熱點資料),新插入緩衝池中的頁先放在midpoint的位置,如果新插入的頁一來就移動到new列表的話可能會導致new列表中的某些活動也被移除到old列表中,比如表掃描操作一次性可能需要訪問很多的資料頁而這些資料頁可能以後很少被使用,新插入的頁何時才會被被放入new列表中呢,為了解決這個問題innodb引入了innodb_old_blocks_time引數,該引數用來控制新插入的資料頁在mid位置多久後才被加入到new列表中。

檢視midpoint的位置,如果覺得熱點資料空間需要更多可以將該值設小
show variables like 'innodb_old_blocks_pct'

查詢
innodb_old_blocks_time值,單位毫秒,預設是1000毫秒即1秒
show variables like 'innodb_old_blocks_time'

 

檢視緩衝池中所有頁的資訊,包括空閒頁,所有的資料頁*16KB其實也就是緩衝池的總大小.
select * from information_schema.INNODB_BUFFER_PAGE;

檢視LUR列表的資訊,包括new list和old list但是不包括free list,表中的欄位記錄了當前的資料頁的資訊,包括緩衝池ID,頁的型別(資料頁、索引頁、undo log、other),表名,索引名,是否是old list的頁,是否屬於壓縮頁(可以將原本16K的頁壓縮為1K、2K、4K、8K),壓縮頁的大小,是否屬於髒頁。
select POOL_ID,LRU_POSITION,SPACE,PAGE_TYPE,FLUSH_TYPE,NEWEST_MODIFICATION,OLDEST_MODIFICATION,INDEX_NAME,DATA_SIZE,COMPRESSED_SIZE,COMPRESSED,IS_OLD from information_schema.INNODB_BUFFER_PAGE_LRU;

OLDEST_MODIFICATION>0表示髒頁的數量也就是(modified db pages)
IS_OLD='YES'代表OLD List頁
COMPRESSED<>0代表壓縮頁

flush list:值的就是LRU中的髒頁,flust list存在於New List中,即OLDEST_MODIFICATION>0(modified db pages)

 

3.日誌緩衝(log buffer):對應innodb日誌檔案

檢視重做日誌緩衝
show variables like 'innodb_log_buffer_size%';

InnoDB儲存引擎首先將重做日誌資訊先放入到重做日誌緩衝中,然後按照一定的頻率將其重新整理到重做日誌檔案當中。預設緩衝大小是8M,8M基本可以滿足需求,不需要配置太大的重做日誌緩衝。

重新整理機制:

1.Master Thread 每一秒將重做日誌緩衝重新整理到重做日誌檔案;

2.每個事務提交時會將重做日誌緩衝重新整理到重做日誌檔案;

3.當重做日誌緩衝池剩餘空間小於1/2時

注意:innodb_log_buffer_size的大小應該要比最大的事務大小要打,否則事務還未提交innodb_log_buffer_size就已經寫滿就需要進行重新整理操作,會造成一個事務需要多次進行磁碟日誌重新整理操作,導致效率低。

 

4.額外的記憶體

平時我們的伺服器MySQL程式所使用的記憶體會比配置的InnoDB緩衝池的記憶體要大,那是因為MySQL除了緩衝池中快取的記憶體額外還需要一部分記憶體用來控制緩衝池內部的一些資源資訊,比如LRU、鎖資源、等待等。

 

CheckPoint機制

為了解決CPU和磁碟直接速度的問題採用了緩衝池,所以對資料的操作都是先在緩衝池中完成,緩衝池中的資料頁往往比磁碟上的資料頁要新,我們將在緩衝池中已經修改但是還未應用到磁碟的資料頁叫“髒頁”,資料頁最終還是需要更新到磁碟中,中間會涉及到CheckPoint機制。

同時為了解決因為突然伺服器停機導致緩衝池中還未來得及重新整理到磁碟的髒頁丟失的問題,加入了重做日誌檔案(重做日誌檔案預設是配置2個,預設名稱是ib_logfile開頭,重做日誌檔案預設大小是48M,兩個重做日誌檔案採取迴圈寫的方式),當事務提交時先寫重做日誌,當發生伺服器停機後可以通過重做日誌來完成恢復(伺服器重啟之後自己預設會恢復),所以得保證重做日誌檔案有剩餘空間,預設機制是當重做日誌檔案空間達到75%-90%時就重新整理一部分髒頁到磁碟同時清空對應的重做日誌空間。

每次重新整理多少頁到磁碟:

Sharp Checkpoint:資料庫關閉時將所有髒頁都重新整理回磁碟,預設方式,引數:innodb_fast_shutdown=1

Fuzzy Checkpoint:重新整理部分髒頁,具體分為以下四種情況

1.Master Thread Checkpoint

Master Thread每隔幾秒鐘從緩衝池中將髒頁重新整理回磁碟

2.FLUSH_LRU_LIST CheckPoint

在5.6版本之後需要保證LRU預設存在1024個可用頁,如果可用頁不足1024頁重新整理部分髒頁回磁碟,通過引數“innodb_lru_scan_dapth”配置。

3.Async/Sync Flush Checkpoint

指的是因為重做日誌檔案空間不足導致的同步或非同步重新整理髒頁回磁碟,當重做日誌空間已使用的空間達到75%-90%就觸發非同步重新整理,如果超過90%就觸發同步重新整理,一般不會觸發同步重新整理操作,除非重做日誌檔案太小並且進行LOAD DA他的BULK INSERT操作。

4.Dirty Page too much

保證緩衝池中髒頁的比例,當緩衝池中的髒頁比例達到75%時就觸發重新整理髒頁操作,通過引數“innodb_max_dirty_pages_pct”配置。

 

總結

innodb儲存引擎的概念非常的多,隨便一個知識點都不止一篇文章可以寫下,所以本篇只是會整體做一個描述後面會針對每一個知識點進行更細的分析。

 

 

 

 

備註:

    作者:pursuer.chen

    部落格:http://www.cnblogs.com/chenmh

本站點所有隨筆都是原創,歡迎大家轉載;但轉載時必須註明文章來源,且在文章開頭明顯處給明連結。

《歡迎交流討論》

相關文章