MySQL學習之InnoDB結構探秘
InnoDB架構圖
內(nèi)存結構
Buffer Pool
why buffer pool ?
InnoDB是基于磁盤存儲,其存儲的最基本單元是頁,大小為16KB。而CPU和磁盤之間速度相差懸殊,所以通常使用內(nèi)存中的緩沖池來提高性能。
what is buffer pool ?
緩沖池里主要緩存了:
data page 數(shù)據(jù)頁
index page 索引頁
insert buffer
what is insert buffer ?
插入緩沖, 用于將多個insert操作合并成一個,減少IO開銷,提高插入性能。只能用在非唯一的輔助索引。
why ?
插入主鍵索引時是順序的,不需要隨機IO,速度會很快。但對于非唯一的輔助索引,插入的葉子節(jié)點是分散的,需要離散的訪問索引頁。
how does it work ?
對非唯一輔助索引,索引的修改并非實時更新索引樹的葉子節(jié)點,而是把若干個對同一頁的更新操作緩存起來,合并為一次操作,從隨機IO轉(zhuǎn)為順序IO,減少IO次數(shù),提高寫入性能。
流程:
先判斷要更新的索引頁,是否在緩沖池中
- 若是,直接插入
- 若不是,則存入Insert Buffer,后交給Master Thread 來進行合并
extend :
一開始只針對INSERT操作,所以叫insert buffer,后來能夠支持 INSERT/UPDATE/DELETE,所以改叫change buffer了
若是唯一索引,在插入時需要檢查索引列的值是否存在,故在修改索引之前,需要把相關的索引頁讀出來,去判斷是否唯一,這時Insert Buffer就失效了。
lock info 鎖信息
data dictionary 數(shù)據(jù)字典(主要包括了一些元數(shù)據(jù)信息,如表結構信息)
adaptive hash index 自適應hash索引,InnoDB為熱點頁建立的索引,用以提高查詢效率
how does it work ?
數(shù)據(jù)庫的讀操作,會先判斷欲讀取的頁是否在緩沖池中,若是,則命中緩沖;否則,從磁盤上讀取,并將讀取到的頁放入緩沖池。
數(shù)據(jù)庫的寫操作,是先修改緩沖池中的頁,再以一定頻率,將緩沖池刷新到磁盤。將數(shù)據(jù)從緩沖池刷新到磁盤,是通過一種checkPoint的機制完成的
practice ?
可通過配置參數(shù)innodb_buffer_pool_size
來設置緩沖池大小
可以看到本機的mysql緩沖池大小為134217728B,換算后是128MB
Redo log buffer
why redo log buffer ?
當緩沖池中的頁是臟頁(修改數(shù)據(jù)時,是先修改緩沖池中的數(shù)據(jù),此時緩沖池中的數(shù)據(jù)和磁盤上不一致,稱為臟頁)時,需要通過某種機制將臟頁刷新到磁盤。若緩沖池中一有數(shù)據(jù)頁發(fā)生改變,就馬上刷新磁盤,效率會很低。所以InnoDB采用Write Ahead Log策略,事務提交時,先將redo log寫入磁盤,這樣就認為臟頁已經(jīng)寫入到磁盤了。之后再通過checkpoint機制擇時將臟頁真正寫入磁盤,臟頁真正寫入磁盤后,就可以刪掉對應的redo log了。若臟頁還沒寫入磁盤,發(fā)生了宕機,則由于redo log已經(jīng)成功寫入磁盤,故可以通過redo log進行數(shù)據(jù)恢復。
redo log保證了事務的持久性。寫redo log時,先將redo log放入redo log buffer,再將redo log按一定策略刷新到磁盤,這是通過innodb_flush_log_at_trx_commit
參數(shù)來配置的,參數(shù)名在不同的mysql版本或許有不一樣,通過如下命令可以查看:
show variables like 'innodb_flush%';
innodb_flush_log_at_trx_commit參數(shù)配置有3個取值:0,1,2 其含義如下圖所示
innodb_flush_log_at_trx_commit屬性可以控制每次事務提交時InnoDB的行為。當屬性值為0時,事務提交時,redo log被寫到redo log buffer,然后等待主線程按時寫入;當屬性值為1時,事務提交時,會將redo log寫入文件系統(tǒng)緩存,并且調(diào)用文件系統(tǒng)的fsync,將文件系統(tǒng)緩沖中的數(shù)據(jù)真正寫入磁盤存儲,確保不會出現(xiàn)數(shù)據(jù)丟失;當屬性值為2時,事務提交時,也會將日志文件寫入文件系統(tǒng)緩存,但是不會調(diào)用fsync,而是讓文件系統(tǒng)自己去判斷何時將緩存寫入磁盤。
當參數(shù)值為0時,寫入效率最高,但是數(shù)據(jù)安全最低;參數(shù)值為1時,寫入效率最低,但是數(shù)據(jù)安全最高;參數(shù)值為2時,二者都是中等水平。一般建議將該屬性值設置為1,以獲得較高的數(shù)據(jù)安全性,而且也只有設置為1,才能保證事務的持久性。
redo log buffer的大小可以通過innodb_log_buffer_size去控制
?Double Write Buffer
雙寫緩沖,和磁盤文件中系統(tǒng)表空間里的Double Write Segment一起解決了頁的部分寫入失效問題。
MySQL數(shù)據(jù)庫IO的最小單位是16KB,文件系統(tǒng)(File System)IO的最小單位是4KB,磁盤IO的最小單位是512B。(具體的大小可能有差異,但意思就是這么個意思,MySQL的基本存儲單位和文件系統(tǒng)的基本存儲單位大小不一致)。由于MySQL的1個單位(頁),相當于文件系統(tǒng)中的4個單位,在將內(nèi)存中的臟頁刷新到磁盤時,一頁會分4次進行寫入,若在寫入過程中發(fā)生意外情況,比如斷電,宕機,則可能成功寫入2次,即寫入了8KB,那另外8KB還是舊的數(shù)據(jù),這叫做部分寫失敗,導致這一頁的數(shù)據(jù),一半是新的,一半是舊,數(shù)據(jù)不完整,成為壞頁,最終數(shù)據(jù)不一致。此時redo log 也無能為力,因為redo log記錄的是對物理頁的修改操作,此時頁本身已經(jīng)損壞,再對損壞的頁應用修改操作,也無法恢復為完整數(shù)據(jù)。
Double Write就是為了解決這個問題。
Double Write 由2部分組成
- 內(nèi)存中的Double Write Buffer(2M)
- 磁盤共享表空間中的Double Write Segment(2M)
它的工作機制是這樣的
- 當觸發(fā)了臟頁刷新時,臟頁并不直接寫入磁盤文件,而是先拷貝到內(nèi)存中的Double Write Buffer
- 接著將Double Write Buffer,分兩次寫入到共享表空間中,每次寫1MB
- 最后再將Double Write Buffer中的臟頁數(shù)據(jù),寫入到實際的各個表空間里,寫入完成后,即標記對應的Double Write 數(shù)據(jù)可被覆蓋
若發(fā)生意外宕機等情況,先從共享表空間中取出Double Write數(shù)據(jù),復制到表空間中,再應用redo log,這樣即完成了數(shù)據(jù)恢復。
優(yōu)點:
提高了數(shù)據(jù)的可靠性
缺點:
由于Double Write 實際是一個物理文件,即是一個file,它會導致操作系統(tǒng)進行更多的fsync刷盤操作,所以它會降低mysql的性能。然而,double write buffer往磁盤寫的時候是順序?qū)懭耄阅芎芨摺?/p>
可以關閉Double Write的場景
- 頻繁的DML
- 不擔心數(shù)據(jù)損壞和丟失
- 系統(tǒng)主要負載集中在寫操作
簡單來說,就是加了一個中間層,先將要寫入磁盤的數(shù)據(jù),暫存到一個中繼站,成功存到中繼站之后,再進行實際的寫磁盤,寫完磁盤后,再告訴中繼站說,剛才暫存到你那里的數(shù)據(jù)我已經(jīng)落盤了,你可以把它標記為無用數(shù)據(jù)了。相當于拿這個中繼站做了數(shù)據(jù)的保險。如果在實際寫磁盤時,發(fā)生意外,那么損壞的數(shù)據(jù)塊,我可以從中繼站那里拿到一份完整的拷貝,保證了數(shù)據(jù)的完整性。
磁盤文件
表空間
系統(tǒng)表空間(共享表空間 ibdata1)
它是被多個表共享的,可以通過
innodb_data_file_path
參數(shù)對系統(tǒng)表空間進行配置
# 格式 innodb_data_file_path = datafile1[,datafile2] # 可以指定多個文件,共同組成系統(tǒng)表空間 innodb_data_file_path = /db/ibdata1:1000M;/db/ibdata2:1000M # 設置了這個參數(shù)后,所有基于InnoDB的表,都會被存儲到系統(tǒng)表空間
- 數(shù)據(jù)字典(各種元數(shù)據(jù),如表結構的定義)
- Double Write Buffer
- Insert Buffer (Change Buffer)
- undo log
- 在系統(tǒng)表空間創(chuàng)建的表數(shù)據(jù),索引數(shù)據(jù)
用戶表空間(獨立表空間 ibd)
# 開啟獨立表空間 innodb_file_per_table = 1 # 設置這個參數(shù)后,每個表都是一個單獨的 .ibd 文件
我本機的MySQL是默認開啟了這個參數(shù)
所以都是一個表一個ibd文件
但是獨立表空間里,只存了數(shù)據(jù),索引,插入緩沖bitmap。其余的信息還是存在系統(tǒng)表空間。
重做日志文件
redo log :
一般InnoDB的數(shù)據(jù)目錄下,會有2個名為ib_logfile0和ib_logfile1的文件,這就是redo log文件
每個InnoDB引擎的表至少要有1個重做日志組(group),一個group下至少有2個重做日志。為了得到更高的可靠性,用戶可設置多個鏡像日志組
InnoDB根據(jù)checkpoint對2個文件進行循環(huán)寫入。
可通過innodb_log_file_size設置redo log的大小。若設置太大,數(shù)據(jù)丟失時,恢復可能要花很長時間;若設置太小,則會導致checkpoint進行頻繁檢查,并將臟頁刷新到磁盤,導致性能抖動。
重做日志的落盤機制在上面的redo log buffer里已經(jīng)說明,簡單總結起來就是2個機制:Write Ahead Log + Force Log at Commit
這兩者保證了事務的持久性
一次寫操作的事務流程如下圖所示:
若發(fā)生了崩潰,則恢復數(shù)據(jù)的過程如下圖所示:
binlog是維護在SQL Layer層的,故不包含在InnoDB中。
以上就是MySQL學習之InnoDB結構探秘的詳細內(nèi)容,更多關于InnoDB結構探秘的資料請關注腳本之家其它相關文章!
相關文章
MySQL中Like模糊查詢速度太慢該如何進行優(yōu)化
在業(yè)務場景中經(jīng)常會用到like模糊查詢,但是大家都知道,like是用不到索引的,所以當數(shù)據(jù)量非常大時,速度會非常慢,這篇文章主要給大家介紹了關于MySQL中Like模糊查詢速度太慢該如何進行優(yōu)化的相關資料,需要的朋友可以參考下2021-12-12mysql 5.7.17 winx64解壓版安裝配置方法圖文教程
這篇文章主要為大家詳細介紹了mysql 5.7.17 winx64解壓版安裝配置方法圖文教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-06-06