MySQL InnoDB存儲引擎


介紹

 本篇文章是對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 DATA的BULK INSERT操作。

4.Dirty Page too much

保證緩沖池中臟頁的比例,當緩沖池中的臟頁比例達到75%時就觸發刷新臟頁操作,通過參數“innodb_max_dirty_pages_pct”配置。

 

總結

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

 

 

 

 

備注:

    作者:pursuer.chen

    博客:http://www.cnblogs.com/chenmh

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

《歡迎交流討論》


免責聲明!

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



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