MySQL存儲引擎InnoDB原理拆解以及設計深度剖析
MySQL記錄存儲以Page(頁)來劃分土居。
頁頭:記錄頁面的控制信息派桩,共占56字節(jié)阴挣,包含頁的左右兄弟頁面指針断序、頁面空間使用情況等年栓。
虛記錄:最大虛記錄:比頁面最大主鍵還大拆挥。 最小虛記錄:比頁面最大主鍵還小。
記錄堆:行記錄存儲區(qū)
自由空間鏈表:鏈表關聯(lián)被刪除的記錄用來重復利用空間
未分配空間:頁面未使用的存儲空間某抓。
Slot區(qū):
頁尾:存儲頁面的校驗信息8個字節(jié)纸兔。
頁內記錄維護
- 順序保證
- 物理有序:非順序插入需要移動數(shù)據(jù),插入效率較低否副,查找效率高汉矿。
- 邏輯有序:物理無序,鏈表連接邏輯數(shù)據(jù)备禀,插入效率高洲拇,查找效率低。
- InnoDB采用的邏輯有序曲尸,在查詢中有進行優(yōu)化赋续。
page 與 page關聯(lián), 主鍵和主鍵關聯(lián)組成順序另患。
- 插入策略
- 自由空間鏈表:InnoDB優(yōu)先使用
- 未使用空間:
- 頁內查詢
- 遍歷:邏輯有序
通過最小虛記錄->最小rec->逐漸遞增->最大虛記錄
Slot 按照一定規(guī)律指向rec纽乱,可以對記錄按照一定規(guī)律進行做類似二分加快查找。
MySQL InnoDB存儲引擎內存管理
- 預分配內存空間 以塊形式加載
- 數(shù)據(jù)以頁為單位加載
- 數(shù)據(jù)內外存交換 將內存塊內容發(fā)生改變后寫入磁盤柴淘,從磁盤加載新的塊加載入硬盤
- 內存池
- 頁面映射 磁盤動態(tài)映射到內存上
- 頁面數(shù)據(jù)管理
- 空閑頁
- 數(shù)據(jù)頁
- 臟頁:被修改后的內存頁迫淹,要將其寫入磁盤。
- 數(shù)據(jù)淘汰(數(shù)據(jù)內外存交換) 內存頁都被使用的情況下或需要加載新的數(shù)據(jù)時为严。
- LRU 最長時間最久沒有被使用的數(shù)據(jù)淘汰掉敛熬,使用鏈表結構。
- 保證鏈尾最長時間沒有使用:每次訪問鏈表數(shù)據(jù)時第股,將該數(shù)據(jù)放到鏈表頭应民,就可以保證鏈表最尾為最長時間沒有被使用。
- 為了解決避免熱數(shù)據(jù)被淘汰:訪問時間+頻率。(redis采用方式)
- 兩個LRU表诲锹。一級LRU做內存加載繁仁,二級LRU存放一級LRU特定等級的熱數(shù)據(jù)。
8.InnoDB采用的方式:
Buffer Pool 預分配的內存池
Page Buffer Pool的最小單位
Free List 空間page組成的鏈表
Flush list 臟頁鏈表
Page hash表 維護內存page和文件page的映射關系
LRU 內存淘汰算法:
LRU
(head)LRU_new(tail):(head)LRU_old(tail)以5比3的比例Midpoint指針進行冷熱分離
LRU_new
LRU_old
Midpoint
- 頁面裝載: 磁盤數(shù)據(jù)到內存归园,插入到LRU_old頭部
- 頁面淘汰: Free list中取> LRU中淘汰 > LRU Flush黄虱,將要淘汰的數(shù)據(jù)放入 Free List
3. old 到 new:定義熱數(shù)據(jù)的移動 innodb_old_blocks_time: old區(qū)存活時間大于此值,有機會進入new區(qū)庸诱。存活時間+訪問頻率 - new 到 old:由Midpoint始終指向8/5位置來區(qū)分冷熱數(shù)據(jù)捻浦,并結合
free_page_clock:Buffer Pool淘汰頁數(shù)
LRU_new長度1/4
當前freed_page_clock-上次移動到Header時freed_page_clock LRU_new 長度1/4
MySQL設計思路:減少移動次數(shù)
MySQL事務實現(xiàn)原理拆解以及設計深度剖析
事務特性
- A:原子性 全部成功或全部失敗
- I:隔離性 并行事務之間互不干擾
- D:持久性 事務提交后數(shù)據(jù)改變是永久性的
- C:一致性 數(shù)據(jù)中間狀態(tài)對外不可見,只有最初狀態(tài)和最終狀態(tài)可見
并發(fā)問題
- 臟讀: 讀取到未提交的數(shù)據(jù)
- 不可重復讀: 兩次讀取結果不同
- 幻讀: select操作的到的結果所表征的數(shù)據(jù)狀態(tài)無法支持后續(xù)的業(yè)務操作
隔離級別
- 讀取未提交內容 RU:最低隔離級別桥爽,會讀到其他事務未提交的數(shù)據(jù)(臟讀)
- 讀取提交內容 :事務過程中可以讀取到其他事務已提交的數(shù)據(jù)(不可重復讀)
- 可重復讀 RR:每次讀取相同結果集朱灿,不管其他事務是否提交(幻讀)
- 串行化:事務排隊,隔離級別最高钠四,性能最差
MySQL事務實現(xiàn)原理
-
MVCC
- 多版本并發(fā)控制:解決讀寫沖突盗扒,有兩個隱藏列
- 當前讀:讀當前版本
- 快照讀:讀歷史版本
- 可見性判斷:創(chuàng)建快照這一刻,還未提交的事務缀去。 創(chuàng)建快照之后創(chuàng)建的事務侣灶。
- Read View: 快照讀 活躍事務列表。 列表中最小事務ID朵耕。 列表中最大事務ID炫隶。
-
undo log
- 回滾日志
- 保證事務原子性
- 實現(xiàn)數(shù)據(jù)多版本
- delete undo log淋叶;用于回滾阎曹,提交即清理
- update undo log:用于回滾,同時實現(xiàn)快照讀煞檩,不能隨便刪除
-
redo log
實現(xiàn)事務持久性
記錄修改
用于異炒ο樱恢復
-
循環(huán)寫文件
- Write Pos:寫入位置
- Check Point:刷盤位置
- Check Point -> Write pos: 待落盤數(shù)
-
寫入流程:
- 記錄頁的修改, 狀態(tài)為prepare斟湃。
- 事務提交熏迹,講事務記錄為commit狀態(tài)。
-
刷盤時機:
- innodb_fulsh_log_at_trx_commit 0/1/2
-
意義:
- 體積小凝赛,記錄頁的修改注暗,比寫入頁代價低。
- 末尾追加墓猎,隨機寫變順序寫捆昏,發(fā)生改變的頁不固定。
MySQL鎖實現(xiàn)原理拆解以及設計深度剖析
InnoDB鎖種類
- 鎖粒度:
- 行級鎖
- 作用在索引上
- 聚簇索引和二級索引
- 間隙鎖:鎖一個范圍
- 解決可重復讀模式下的幻讀問題
- GAP鎖不是加在記錄上
- GAP鎖鎖住的位置毙沾,是兩條記錄之間的GAP
- 保證兩次當前讀返回一致的記錄骗卜。
- 表級鎖
- RC級別全表掃描“鎖表”,所有記錄加鎖后返回,然后由MySQL Server層進行過濾寇仓。
- RR級別全鎖举户,會造成性能大幅下降。
- 行級鎖
- 類型:
共享鎖
排它鎖(寫鎖)
當前讀:select for update 遍烦、update 俭嘁、delete,為了更新需要加行級鎖服猪。
有沒有索引/唯一索引/非唯一索引/隔離等級(RC/RR)四種情況來分析鎖
RC會出現(xiàn)幻讀(刪除時插入非唯一索引記錄兄淫,刪除后還可以查到)。死鎖:
并發(fā)事務蔓姚,互相擁有對方需要加鎖對象的鎖捕虽,導致加鎖失敗。