具體細(xì)節(jié) 請(qǐng)去掘金購(gòu)買(mǎi)《MySQL 是怎樣運(yùn)行的:從根兒上理解 MySQL》
redo日志
row_id隱藏列賦值的方式
- 1.服務(wù)器會(huì)在內(nèi)存中維護(hù)一個(gè)全局變量,每當(dāng)向某個(gè)包含隱藏的row_id列的表中插入一條記錄時(shí),就會(huì)把該變量的值當(dāng)作新記錄的row_id列的值,并且把該變量自增1。
- 2.每當(dāng)這個(gè)變量的值為256的倍數(shù)時(shí),就會(huì)將該變量的值刷新到系統(tǒng)表空間的頁(yè)號(hào)為7的頁(yè)面中一個(gè)稱(chēng)之為Max Row ID的屬性處
- 3.當(dāng)系統(tǒng)啟動(dòng)時(shí),會(huì)將上邊提到的Max Row ID屬性加載到內(nèi)存中,將該值加上256之后賦值給我們前邊提到的全局變量
邏輯日志
- 1.簡(jiǎn)單理解記錄的是sql語(yǔ)句
物理日志
- 1.記錄的是4元組數(shù)據(jù),哪個(gè)表空間,哪個(gè)文件,哪個(gè)頁(yè),哪個(gè)偏移位置,插入的字節(jié)內(nèi)容
邏輯物理日志
- 1.redo日志頁(yè)面內(nèi)的操作記錄的是邏輯日志
- 2.redo日志頁(yè)間的操作記錄的是物理日志
- 3.binlog是邏輯日志
- 4.redo是邏輯物理日志,所以partial page時(shí)需要double write介入才能恢復(fù)數(shù)據(jù)
partial page
- 1.比如我們對(duì)一個(gè)頁(yè)進(jìn)行刷新操作,操作一般就斷電了。
- 2.這個(gè)時(shí)候redo因?yàn)槭琼?yè)內(nèi)是邏輯日志,只記錄數(shù)據(jù)的邏輯,而原先的物理位置已經(jīng)被占滿(mǎn)了
- 3.因此只能完全的替換該頁(yè)面,重新使用redo
redo日志解決了什么
- 1.磁盤(pán)的數(shù)據(jù)被load到bufferpool之后,如果我們修改buffer pool了,這些數(shù)據(jù)不會(huì)立馬被刷入到磁盤(pán),那么如何保證事務(wù)的持久性
- 2.如果修改了bufferpool頁(yè)面數(shù)據(jù)就需要立即刷入磁盤(pán),一個(gè)是太浪費(fèi)(一個(gè)頁(yè)有16kb,修個(gè)一個(gè)字節(jié)也刷16KB不合理),二個(gè)是隨機(jī)IO刷起來(lái)慢(因?yàn)橐粋€(gè)事務(wù)可能修改不同的頁(yè),這些頁(yè)在物理上并不一定是連續(xù)的)
- 3.redo日志就是解決上述1和2的問(wèn)題的。
redo日志的優(yōu)點(diǎn)
- 1.占用的空間非常?。捍鎯?chǔ)表空間ID、頁(yè)號(hào)、偏移量以及需要更新的值
- 2.redo日志是順序?qū)懭氪疟P(pán)的
通用的redo日志格式
type
- 1.redo日志的類(lèi)型
space ID
- 1.表空間ID。
page number
- 1.頁(yè)號(hào)
data
- 1.該條redo日志的具體內(nèi)容。
簡(jiǎn)單的redo日志類(lèi)型
- 1.比如更新Max Row ID
MLOG_XBYTE(物理日志)
- 1.標(biāo)識(shí)在頁(yè)面的某個(gè)偏移量處寫(xiě)入了X字節(jié)的redo日志
- 2.多了一個(gè)offset,代表需要修改記錄的起始位置
MLOG_WRITE_STRING(物理日志)
- 1.多了一個(gè)offset和len
- 2.len代表數(shù)據(jù)的長(zhǎng)度
復(fù)雜一些的redo日志類(lèi)型
- 1.一個(gè)語(yǔ)句可能會(huì)更新葉子節(jié)點(diǎn),也有可能更新內(nèi)節(jié)點(diǎn),甚至于產(chǎn)生新的頁(yè)面
- 2.還得需要更新Page Directory中的槽信息。
- 3.Page Header中的各種頁(yè)面統(tǒng)計(jì)信息
- 4.還需要更新上一條記錄的記錄頭信息中的next_record
- 5.把一條記錄插入到一個(gè)頁(yè)面時(shí)需要更改的地方非常多(多個(gè)頁(yè)面)
- 6.因此復(fù)雜的redo日志處理包含物理層面的意思,也得包含邏輯層面的意思
- 7.物理層面看,這些日志都指明了對(duì)哪個(gè)表空間的哪個(gè)頁(yè)進(jìn)行了修改。
- 8.邏輯層面看,在系統(tǒng)奔潰重啟時(shí),并不能直接根據(jù)這些日志里的記載,將頁(yè)面內(nèi)的某個(gè)偏移量處恢復(fù)成某個(gè)數(shù)據(jù),而是需要調(diào)用一些事先準(zhǔn)備好的函數(shù),執(zhí)行完這些函數(shù)后才可以將頁(yè)面恢復(fù)成系統(tǒng)奔潰前的樣子。
MLOG_REC_INSERT
- 1.表示插入一條使用非緊湊行格式的記錄時(shí)的redo日志類(lèi)型。
- 2.Redundant是一種比較原始的行格式,它就是非緊湊的
MLOG_COMP_REC_INSERT
- 1.表示插入一條使用緊湊行格式的記錄時(shí)的redo日志類(lèi)型。
- 2.Compact、Dynamic以及Compressed行格式是較新的行格式,它們是緊湊的
- 3.日志結(jié)構(gòu)比通用的日志額外多了以下字段
- 4.n_fields:記錄該記錄有多少個(gè)字段
- 5.n_uniques:在一條記錄中,需要幾個(gè)字段的值才能確保記錄的唯一性
- 6.fieldX_len:第X個(gè)字段的占用的存儲(chǔ)空間大小
- 7.offset:前一條記錄的地址
- 8.end_seg_len:從該字段可以計(jì)算出當(dāng)前記錄總共占用的存儲(chǔ)空間的大小
- 9.info bits:記錄頭信息的前4個(gè)比特位的值以及record_type的值
- 10.extra_size:記錄額外信息占用的存儲(chǔ)空間大小
- 11.mismatch index:未知作用
- 12.對(duì)于聚簇索引來(lái)說(shuō),n_uniques的值為主鍵的列數(shù),對(duì)于其他二級(jí)索引來(lái)說(shuō),該值為索引列數(shù)+主鍵列數(shù)
MLOG_COMP_PAGE_CREATE
- 1.表示創(chuàng)建一個(gè)存儲(chǔ)緊湊行格式記錄的頁(yè)面的redo日志類(lèi)型。
MLOG_COMP_REC_DELETE
- 1.表示刪除一條使用緊湊行格式記錄的redo日志類(lèi)型。
MLOG_COMP_LIST_START_DELETE
- 1.表示從某條給定記錄開(kāi)始刪除頁(yè)面中的一系列使用緊湊行格式記錄的redo日志類(lèi)型。
MLOG_COMP_LIST_END_DELETE
- 1.與MLOG_COMP_LIST_START_DELETE類(lèi)型的redo日志呼應(yīng),表示刪除一系列記錄直到MLOG_COMP_LIST_END_DELETE類(lèi)型的redo日志對(duì)應(yīng)的記錄為止。
MLOG_COMP_LIST_START_DELETE和MLOG_COMP_LIST_END_DELETE存在的意義
- 1.數(shù)據(jù)頁(yè)中的記錄是按照索引列大小的順序組成單向鏈表的。有時(shí)候我們會(huì)有刪除索引列的值在某個(gè)區(qū)間范圍內(nèi)的所有記錄的需求,這時(shí)候如果我們每刪除一條記錄就寫(xiě)一條redo日志的話(huà),效率可能有點(diǎn)低,
所以提出MLOG_COMP_LIST_START_DELETE和MLOG_COMP_LIST_END_DELETE類(lèi)型的redo日志,可以很大程度上減少redo日志的條數(shù)
MLOG_ZIP_PAGE_COMPRESS
- 1.表示壓縮一個(gè)數(shù)據(jù)頁(yè)的redo日志類(lèi)型。
redo日志格式小結(jié)
Mini-Transaction
- 1.以組的形式寫(xiě)入redo日志
- 2.在執(zhí)行語(yǔ)句的過(guò)程中產(chǎn)生的redo日志被設(shè)計(jì)InnoDB的大叔人為的劃分成了若干個(gè)不可分割的組
- 3.多個(gè)普通redo日志組成一個(gè)完成的redo日志,結(jié)尾是以一個(gè)type=MLOG_MULTI_REC_END結(jié)尾
- 4.當(dāng)然只有一個(gè)redo日志也可以組成一個(gè)組,具體的看type的值
- 5.type字段是一個(gè)字節(jié) 8個(gè)bit,第一個(gè)bit代表該組是否是單一的redo,后面7位代表了redo的日志類(lèi)型。
- 6.對(duì)底層頁(yè)面中的一次原子訪(fǎng)問(wèn)的過(guò)程稱(chēng)之為一個(gè)Mini-Transaction--MTR
- 7.
一個(gè)事務(wù)包含若干個(gè)語(yǔ)句,一個(gè)語(yǔ)句對(duì)應(yīng)若干個(gè)mtr,一個(gè)mtr包含若干個(gè)redo
redo日志的寫(xiě)入過(guò)程
redo log block
- 1.Innodb把mtr生成的redo日志都存放在大小為512字節(jié)的頁(yè)(block)中,該頁(yè)和表空間頁(yè)有所區(qū)別--是共享表空間
- 2.block==log block header,log block body 和log block trailer
- 3.log block header和log block trailer存儲(chǔ)的是一些管理信息,log block body存儲(chǔ)的是redo
log block header
- 1.LOG_BLOCK_HDR_NO:每一個(gè)block都有一個(gè)大于0的唯一標(biāo)號(hào),本屬性就表示該標(biāo)號(hào)值。
- 2.LOG_BLOCK_HDR_DATA_LEN:表示block中已經(jīng)使用了多少字節(jié),初始值為12(因?yàn)閘og block body從第12個(gè)字節(jié)處開(kāi)始)
- 3.LOG_BLOCK_FIRST_REC_GROUP:代表該block中第一個(gè)mtr生成的redo日志記錄組的偏移量(其實(shí)也就是這個(gè)block里第一個(gè)mtr生成的第一條redo日志的偏移量)
- 4.LOG_BLOCK_CHECKPOINT_NO:表示所謂的checkpoint的序號(hào)
log block trailer
- 1.LOG_BLOCK_CHECKSUM:表示block的校驗(yàn)值,用于正確性校驗(yàn)
redo日志緩沖區(qū)
- 1.redo日志也需要緩沖區(qū),其是在服務(wù)器啟動(dòng)時(shí)就向操作系統(tǒng)申請(qǐng)了一大片稱(chēng)之為redo log buffer的連續(xù)內(nèi)存空間
- 2.這片內(nèi)存空間被劃分成若干個(gè)連續(xù)的redo log block
- 3.可以通過(guò)innodb_log_buffer_size來(lái)指定log buffer的大小
- 4.redo日志寫(xiě)入log buffer是順序的,通過(guò)全局變量buf_free來(lái)指明后續(xù)的redo日志應(yīng)該寫(xiě)入到log buffer中的哪個(gè)位置
- 5.并不是每生成一條redo日志,就將其插入到log buffer中,而是每個(gè)mtr運(yùn)行過(guò)程中產(chǎn)生的日志先暫時(shí)存到一個(gè)地方,當(dāng)該mtr結(jié)束的時(shí)候,將過(guò)程中產(chǎn)生的一組redo日志再全部復(fù)制到log buffer中
- 6.根據(jù)5的描述不同事務(wù)的mtr可能是交替寫(xiě)入log buffer的