快速讀懂InnoDB存儲引擎
什么是存儲引擎
存儲引擎位于文件系統(tǒng)(各種數(shù)據(jù),二進(jìn)制形式)之上,各種管理工具(連接池、語義分析器、優(yōu)化器、緩存區(qū)、SQL接口)之下。

存儲引擎功能設(shè)計(jì)
功能豐富性(或者SQL語義支持):
事務(wù)(和文件系統(tǒng)的最大區(qū)別),鎖的粒度(行或者表),全文索引,簇索引,外鍵(這是什么)
事務(wù):
事務(wù)的隔離性由鎖實(shí)現(xiàn),其他ACD由redo log和undo logo實(shí)現(xiàn)。redo log保證事務(wù)原子性(怎么理解?由于數(shù)據(jù)庫設(shè)計(jì)是先寫redo,再執(zhí)行真正修改數(shù)據(jù)頁。所以redo一定是個完整的事務(wù),才會修改數(shù)據(jù)頁)和持久性(怎么理解?持久化到硬盤)。undo log保證事務(wù)一致性(數(shù)據(jù)沖突時的恢復(fù))。
redo 寫法是數(shù)據(jù)庫一直順序?qū)?,無需讀。由于沒有使用O_DIRECT裸寫盤,所以每次寫redo 必須fsync到硬盤。
另外這里還有提到的是binlog,區(qū)分的是binlog是數(shù)據(jù)庫容災(zāi)的范籌(記錄的是sql語句,在事務(wù)提交的時候才會寫)。而redo是innodb產(chǎn)生的(修改頁的物理二進(jìn)制日志,隨事務(wù)進(jìn)行而并發(fā)寫)。而且在寫redo是以日志塊大小和磁盤扇區(qū)一樣。都是512字節(jié)。所以重寫日志寫入具有原子性。redo的物理二進(jìn)制日志,以不記錄sql語句執(zhí)行過程,而記錄sql執(zhí)行后的頁結(jié)果。由此具有冪等性(執(zhí)行多次等同于執(zhí)行一次,分布式網(wǎng)絡(luò)的不可靠 由于多次重新調(diào)用接口,必須保證冪等性)。
一個問題是,基于硬盤的數(shù)據(jù)庫會把數(shù)據(jù)寫在內(nèi)存中,同時對數(shù)據(jù)庫的修改最初也是改在內(nèi)存上,怎么落地呢(checkpoint檢查點(diǎn)機(jī)制)。事務(wù)數(shù)據(jù)庫為了保證ACID的D一般會使用先寫redo log,在修改頁。
undo幫助事務(wù)回滾和MVCC功能。
表鎖、行鎖:
鎖機(jī)制分為latch(輕量級的鎖,分為mutex和rwlock。這個是內(nèi)部鎖機(jī)制,保證并發(fā)線程操作臨界資源的正確性,通常沒有死鎖檢測機(jī)制, 比如查看mutex的方法是show engine innodb mutex;)和lock(粒度為事務(wù),可以是表、頁、行,有死鎖檢測機(jī)制)。
死鎖檢測機(jī)制有:順序獲取多個鎖(latch只有這個機(jī)制),waits-for graph(圖死鎖檢測),過期機(jī)制。
MVCC機(jī)制(解決鎖帶來爭用的分布式并發(fā)訪問問題)
自增長鎖:給每個插入賦予一個唯一增加的id,每個插入獲取到這個id,就可以釋放表鎖。通過減少鎖的持有時間,提高并發(fā)插入效率。
查看當(dāng)前事務(wù)隔離級別:
- mysql> SELECT @@tx_isolationG;
- *************************** 1. row ***************************
- @@tx_isolation: REPEATABLE-READ
幻讀和臟讀:臟讀都不好嗎?在slave節(jié)點(diǎn)可以修改innodb的默認(rèn)事務(wù)隔離級別REPEATEDLY READ為READ UNCONMITTED,允許讀到不那么準(zhǔn)確的數(shù)據(jù)。
不可重復(fù)讀:一般不可重復(fù)讀是可以接受的,因?yàn)樗x到的是提交的數(shù)據(jù),而臟讀是讀到未提交的數(shù)據(jù)。如Oracle和SQL Server設(shè)置的事務(wù)隔離級別是READ CONMIITTED,則會出現(xiàn)不可重復(fù)讀現(xiàn)象。
丟失更新:一個事務(wù)更新會被另一個事務(wù)更新所覆蓋,從而產(chǎn)生數(shù)據(jù)不一致。基本數(shù)據(jù)庫任何隔離級別,不會產(chǎn)生。
數(shù)據(jù)存儲設(shè)計(jì):
支持B樹索引,支持hash索引,數(shù)據(jù)壓縮存儲,數(shù)據(jù)表緩存(或者只索引緩存),數(shù)據(jù)文件加密,存儲效率,內(nèi)存消耗,硬盤消耗,塊插入速度,查詢緩存,MVCC(解決并發(fā)數(shù)據(jù)一致性問題)。
B+樹索引/自適應(yīng)hash索引:
B樹(Blance樹或者平衡樹):關(guān)系型數(shù)據(jù)庫最常用拿來做索引的。從AVL(平衡二叉樹演化而來)。
B+樹=B樹+索引順序訪問。包含樹枝節(jié)點(diǎn)和葉子節(jié)點(diǎn)。所有的數(shù)據(jù)放在葉子節(jié)點(diǎn)。每一個葉子節(jié)點(diǎn)互相有序順序連接。樹根節(jié)點(diǎn)指引著查找到葉子節(jié)點(diǎn)的路徑。由于不斷的插入和刪除,同時B+樹會通過旋轉(zhuǎn)保持平衡。
B+索引本身并不是找到具體的一條記錄,而是找到該記錄所在的頁。數(shù)據(jù)頁把載入到內(nèi)中,然后通過頁目錄在進(jìn)行二叉查找。因?yàn)樵趦?nèi)存查找很快。
聚集索引:按照表的主鍵構(gòu)建的B+樹。
輔助縮影:葉子節(jié)點(diǎn)存放的不是數(shù)據(jù),而是捷徑,指引到找到所有數(shù)據(jù)的地方。
數(shù)據(jù)的區(qū)分度:Cardinality
自適應(yīng)哈希索引:innodb根據(jù)查找頻度,創(chuàng)建hash索引。將o(logn)的查找復(fù)雜度提高最快o(0)(最慢o(n))的速度。哈希索引不對范圍查找有效。
壓縮空間和加密安全:
記錄在文件可以是普通模式或者reduction模式。
容災(zāi)機(jī)制:
備份機(jī)制,備份恢復(fù)(備份快照點(diǎn)記錄)。熱備,冷備,溫備。
新上一臺備機(jī)的備份順序是記住當(dāng)前主數(shù)據(jù)庫的LSN(log squence number),導(dǎo)出主數(shù)據(jù)庫的當(dāng)前數(shù)據(jù)庫并在備機(jī)導(dǎo)入。設(shè)置LSN同步點(diǎn)。
innodb特性
特性:
- innodb架構(gòu):多線程模型(Master,IO,Purge,Page Cleaner),數(shù)據(jù)刷新到硬盤才是sql(事務(wù))執(zhí)行完的標(biāo)志嗎。purge是完成事務(wù)提交后情況undo log。
- 內(nèi)存的消耗大(大在哪里?)。內(nèi)存消耗在具體在緩沖區(qū)。緩沖區(qū)除了保護(hù)有數(shù)據(jù)頁,索引頁,還有undo頁,插入緩沖。自適應(yīng)hash索引、鎖信息、字典信息。為什么innodb的內(nèi)存會比其他的存儲引擎大呢?
- 什么是數(shù)據(jù)庫實(shí)例(類似于服務(wù)器的進(jìn)程,數(shù)據(jù)庫是數(shù)據(jù)文件)
- 緩沖區(qū)的基本管理思路是LRU。37為距離LRU追加尾部的37%位置,并且只有在mid位置當(dāng)超過block_times的時候才要可以會被移到mid的熱點(diǎn)。當(dāng)然用戶預(yù)估自己的熱點(diǎn)數(shù)據(jù),適當(dāng)?shù)迷黾觤id之前的熱點(diǎn)區(qū)域。其中page made young和page not made young就表示了頁從old移到new或者由于block_time的限制,old沒能移到new。從information_schema數(shù)據(jù)庫的select * from innodb_buffer_pool_statsG;可以獲取到??梢钥吹竭@里還是很多old往new的遷移過程當(dāng)中被block住。(我覺得這里made yong的過程中,是不是有很多熱點(diǎn)數(shù)據(jù),有沒有必要把mid位置調(diào)長些)。第一個實(shí)例:緩沖區(qū)空間size:8192*16K=128M。LRU表項(xiàng)用DATABASE_PAGES表示。FREE_BUFFERS是可利用的頁。
- 主線程:每秒鐘循環(huán)和每10秒鐘循環(huán)
- 重做日志的LSN(Log Sequeence Number)標(biāo)記版本。
- Sharp Checkpoint和Fuzzy Checkpoint(主線程定時的刷新,LRU頁不夠必須刪除尾巴頁,重做日志不可用,臟頁太多)
- 數(shù)據(jù)庫的容災(zāi):重做日志+LRU。LRU溢出需要寫磁盤。重做日志由于磁盤空間必須部分刪除需要寫磁盤
innodb關(guān)鍵特性:
- 插入緩沖:針對非聚集索引的插入或者更新。針對非唯一輔助索引。
- 兩次寫:寫的壓力大不大,總共寫內(nèi)存多少Innodb_dblwr_pages_written(真實(shí)反映數(shù)據(jù)庫的),硬盤持久化多少次Innodb_dblwr_writes
- 自適應(yīng)hash索引:要求訪問模式比較單一
- AIO:AIO的好處和壞處。:| innodb_flush_neighbors | 1 |
- 刷新鄰接頁(預(yù)讀)。但是如果是本來 就是iops比較高的存儲設(shè)備還需要這個嗎,因?yàn)檫@個是對機(jī)械硬盤相鄰數(shù)據(jù)寫入做優(yōu)化,或者有沒有可能領(lǐng)接頁寫入刷新了 又很快變?yōu)榕K頁。
查看當(dāng)前數(shù)據(jù)庫運(yùn)行性能
- show global status like 'com_select';列出 自數(shù)據(jù)庫啟動以來的所有連接

查看數(shù)據(jù)庫的線程數(shù)據(jù)來窺探性能

查看緩存區(qū)狀態(tài)

LRU查看
- mysql> show variables like '%old_block%';
- +------------------------+-------+
- | Variable_name | Value |
- +------------------------+-------+
- | innodb_old_blocks_pct | 37 |
- | innodb_old_blocks_time | 1000 |
- +------------------------+-------+
查看當(dāng)前數(shù)據(jù)庫的運(yùn)行狀態(tài)還有
- show engine innodb status。
- show variables;
- show status;
備份相關(guān)
- show binlog events in 'bin-log.000004'G
- show master status
- show slave status
- show binary logs;查看所有的二進(jìn)制日志
- show variables like '%sync_binlog%'
- binlog文件轉(zhuǎn)換
- 每次服務(wù)器啟動都開啟一個新的二進(jìn)制日志。文件大小超過限制將會創(chuàng)建一個新的文件。