邏輯存儲結構 邏輯存儲結構圖 表空間 表空間文件在Linux下存放在 /var/lib/mysql文件中的 xxx.ibd 文件就是表空間文件 表空間文件用來存儲,記錄,索引等數據。 段 段分為,數據段(Leaf node segment) ,索引段(Non-leaf node segment),回 ...
邏輯存儲結構
邏輯存儲結構圖
-
表空間
表空間文件在Linux下存放在 /var/lib/mysql文件中的 xxx.ibd 文件就是表空間文件
表空間文件用來存儲,記錄,索引等數據。
-
段
段分為,數據段(Leaf node segment) ,索引段(Non-leaf node segment),回滾段(Rollback segment),InnoDB是索引組織表,數據段就是B+樹的葉子節點,索引段就是非葉子節點,段用來管理Extend(區)。
一個段相當於一張表
-
區
區是表空間的單元結構,每個區大小為1M,預設情況下InnoDB存儲引擎頁大小為16k,一個區一共16個連續的頁。
-
頁
頁,是InnoDB存儲引擎磁碟管理的最小單元。
每個區預設16KB,為了保證頁的連續性,InnoDB存儲引擎每次從磁碟申請4到5個區。
-
行
行指的是InnoDB存儲的數據
表結構中倆個隱藏欄位
Trx_id:最後一次操作事務的id
Roll pointer:指針,指向增刪改之前的數據,可以拿這個找到修改之前的數據。
架構
MySQL5.5版本後,預設使用InoDB存儲引擎。
它擅長事務處理,具有崩潰恢復性特性!
下圖為InnoDB架構圖,左邊為記憶體結構,右邊為磁碟結構。
記憶體結構
Buffer Pool(緩衝池)
緩衝池是主記憶體的一個區域,裡面可以緩存磁碟上經常操作的真實數據。
在執行增刪改查操作的時候,先操作緩存池中的數據(如果沒有,從磁碟載入並且緩存)
然後以一定頻率刷新到磁碟,從而減少磁碟IO,加快處理速度
在緩存池中有一塊一塊的,這個是頁。
緩存池以頁為單位,底層採用鏈表數據結構管理Page。
根據狀態將Page分為三類:
- free page :空閑頁,未被使用的頁。
- clean page :被使用的頁,數據沒有被修改過。
- dirty page :臟頁,被使用的頁,頁中數據和磁碟中數據不一致。
Change Buffer(更改緩存區)
介紹
更改緩存區,主要針對非唯一的二級索引。
在執行DML語句時,如果這些數據頁不在Buffer Poor中,不會直接操作磁碟,而是將數據變更在更改緩存區Change Buffer中。
在未來數據被讀取的時候,再將數據合併恢復到Buffer Pool中,再將合併後的數據刷新到磁碟中。
意義
和聚集索引不同,二級索引是非唯一的!
並且二級索引以相對隨機的順序插入。
同樣的刪除和更新可能會影響索引樹中不相鄰的二級索引頁,如果每一次都操作磁碟,會造成大量磁碟IO。
有了ChangeBuffer後,我們可以在緩衝池中進行合併處理減少磁碟IO
Log Buffer(日誌緩存區)
日誌緩存區,用來保存要寫入磁碟中的log日誌數據(redo log 、undo log)。
預設大小16MB,日誌緩存區的日誌會定期刷新到磁碟中。如果需要更新、插入、或刪除多行的事務,增加日誌緩存區大小可以節約磁碟IO
在系統變數中設置即可
關鍵字:
innodb_log_buffer_size 緩存區大小
innodb_flush_log_at_trx_commit 日誌刷新到磁碟的時機
1代表的是日誌在每次事務提交時寫入並刷新到磁碟
0代表每秒將日誌寫入並刷新到磁碟一次
2代表日誌在每次事務提交後寫入,並且每秒刷新到磁碟一次
Adaaptive Hash index(自適應哈希索引)
自適應哈希索引,用於優化Buffer Pool數據的查詢。
InnoDB存儲引擎會監控表上各索引頁的查詢,如果觀察到hash索引可以提高速度,就會建立hash索引。
這個叫自適應哈希索引
可以在系統變數中查詢是否開啟自適應哈希索引
關鍵字是 adaptive_hash_index
磁碟結構
System Tablespace(系統表空間)
系統表空間是change Buffer的存放區域。
關鍵字:innodb_data_file_path
系統表空間存放路徑
File-Per-Table Tablespaces
存放每個表的獨立表空間
預設是開啟的-->開啟後代表每一張表都會生成對應的表空間文件。
xxx.ibd結尾的文件都是表的表空間文件
查看變數 innodb_file_per_table看是開的還是關的
裡面存放了表結構,表數據,索引
General Tablespaces(通用表空間)
通用表空間,需要手動通過
create tablespace 表空間名 add datafile '表空間對應的磁碟文件.ibd' engine=innodb;
創建通用表空間。
在創建表的時候可以指定該表空間
create table 表名(
欄位....
)engine=存儲引擎 tablespace 表空間名;
Undo Tablespaces(撤銷表空間)
撤銷表空間,MYSQL實例在初始化的時候會自動創建倆個預設的undo表空間(初始大小16M)用來存放undo log日誌
預設叫 undo_001和undo_002
Temporary Tablespaces(臨時表空間)
用來存儲用戶創建的臨時表。
Doublewrite Buffer Files(雙寫緩衝區)
雙寫緩衝區,innoDB存儲引擎會將數據頁沖Buffer Pool刷新到磁碟前,先將數據頁寫入雙寫緩衝區文件中,便於系統異常時恢複數據。
雙寫緩衝區文件:xxx.dblwr
Redo Log(重做日誌)
用來實現事務的持久性。
該日誌文件由倆個部分組成:重做日誌緩衝區(redo log buffer)和重做日誌文件(redo log)
重做日誌緩衝區:是在記憶體中
重做日誌文件:是在磁碟在
事務提交後會把所有修改的信息存放在該日誌中,用於刷新臟頁到磁碟,發生錯誤時,進行數據恢復使用
以迴圈的方式寫入重做文件,涉及到倆個文件:ib_logfile0和ib_logfile1
後臺線程
作用:將Innodb緩衝池的數據在合適的時機刷新到磁碟文件中。
分為四類:
-
Master Thread
核心後臺線程,負責調度其他線程。還負責將緩衝池中的數據非同步刷新到磁碟中,保持數據的一致性。
還包括,臟頁的刷新,合併插入緩衝,undo頁的回收
-
IO Thread
在InoDB存儲引擎中大量使用了AIO來處理IO請求,這樣可以極大提高資料庫性能,IO Thread主要負責以下IO請求的回調
線程類型 預設個數 責任 Read thread 4 負責讀操作 write thread 4 負責寫操作 Log thread 1 負責將日誌緩衝區刷新到磁碟 Insert buffer thread 1 負責將寫緩衝區內容刷新到磁碟 關於AIO(非同步IO)和IO(同步IO)
同步就是在發出一個功能調用時,在沒有得到結果之前,該調用就不返回。也就是必須一件一件事做,等前一件事做完了才能做下一件事。
非同步的概念和同步相對。當一個非同步過程調用發出後,調用者不能立刻得到結果(在此期間,調用者可以去乾一些別的事情)。實際處理這個調用的部件在完成後,通過狀態、通知和回調。
-
Purge Thread
主要用於回收事務已經提交的undo log,在事務提交之後,undo log可能不需要了,就用這個來回收。
-
Page Cleaner Thread
協助Master Thread刷新臟頁到磁碟的線程,他可以減輕Master Thread的工作壓力,減少阻塞。
整個流程
在增刪改查的時候,會操作記憶體結構區域,如果裡面沒有數據就從。磁碟結構中載入,然後進行操作。
最後在特定時間會自動從記憶體結構中刷新到磁碟中。在磁碟中進行持久化保存下來
事務原理
事務
事務是一組操作的集合,它是一個不可分割的工作單位,事務會把所有操作作為一個整體一起向系統提交撤銷操作請求。
這些操作要麼同時成功要麼同時失敗。
事務的四大性質
-
原子性
事務是不可分割的最小操作單元,要麼全部成功,要麼全部失敗。
-
一致性
事務完成時,必須使所有的數據保持一致性。
-
隔離性
資料庫系統提高隔離機制,保證事務在不受外部併發操作影響的獨立環境運行。
-
持久性
事務一旦提交或回滾,他對資料庫的數據改變就是永久的。
事務的原理
事務的原子性,一致性,持久性都是由redo log和undo log實現的
事務的隔離性是由 鎖機制和MVCC實現的。
redo log
重做日誌,記錄的是事務提交時數據頁的物理修改,用來實現事務的持久性。
該日誌文件由倆部分組成:
-
重做日誌緩衝(redo log buffer)
在記憶體中
-
重做日誌文件(redo log file)
在磁碟中
當事務提交後會把所有修改信息都存放到該日誌文件中,用於在刷新臟頁到磁碟中,發生錯誤時,進行數據的恢復。
大概流程:
-
客戶端A對innoDB存儲引擎的表進行增刪改事務操作
-
先訪問記憶體結構中的緩衝池,如果增刪改數據在其中不存在,
就會從磁碟中讀取數據再刷新到緩衝池(這個數據必須是唯一索引,否則會先進入到更改緩衝區)
-
在緩衝池中變成臟頁,並記錄在redolog buffer中,後直接刷新到磁碟中
-
如果臟頁在一段時間後刷新到磁碟中報錯了,可以通過redo log進行恢復。
使用redo log直接刷新到磁碟結構的好處
事務一般是一組多條的增刪改查操作,故事務提交的時候會隨機的操作多條的記錄。
這些記錄會操作多條數據頁,這樣會產生大量的隨機磁碟IO
而直接將redo log文件非同步刷新到磁碟io中,由於它是日誌文件,日誌文件都是追加的,此時是順序磁碟IO,這樣會節約大量的磁碟IO
這種機制叫WAL(Write-Ahead Logging)(先寫日誌)
然後過一段時間臟頁日誌才會刷新到磁碟中。
故倆份日誌是迴圈清理的
事務的redo log日誌是為瞭解決臟頁刷新到磁碟出錯時進行數據的恢復使用的,用來保證數據的持久性
undo log
undo log日誌是用來保證事務的原子性的。
undo log也叫回滾日誌,用於記錄數據被修改前的信息,作用為:提供回滾和MVCC
redo log記錄的是物理日誌!
undo log記錄的是邏輯日誌,可以認為當執行delete 一條記錄時,undo log中會記錄一條對應的insert記錄,反之同理。
當執行rollback時,就可以從undo log中的邏輯記錄讀取到對應內容,從而進行回滾。
Undo log銷毀
undo log在事務執行時產生,事務提交時,並不會馬上刪除undo log,因為這些日誌可能還用於MVCC
Undo log存儲
undo log採用,段的方式進行管理和記錄,存放在前面介紹的rollback segment回滾中,內部包含了1024個undo log segment
這個段是邏輯存儲結構的段哦~
MVCC(多版本併發控制)(高頻面試題)
MVCC的幾個基本概念
當前讀
我們讀取的是記錄的最新版本,讀取時還要保證其他併發事務不能修改當前記錄,會對讀取的記錄進行加鎖,
對於我們日常的操作,如:select...lock in share mode(共用鎖),select...for update,update,insert,delete(排他鎖)
都是一種當前讀。
案例:
在RR的隔離級別下
- 事務A進行查詢操作,事務B進行更新操作並提交事務
- 事務A使用當前讀select...此時讀取的是事務B更新之前的數據(原因是隔離級別)
- 事務A使用select...lock in share mode(當前讀)此時讀取的是事務B更新之後的數據。
快照讀
簡單的select(不加鎖)就是快照讀,讀取的是記錄數據的可見版本,可能是歷史數據,不加鎖是非阻塞讀。
- Read Committed隔離級別:每次select都生成一個快照讀
- Repeatable Read隔離級別:開啟事務後第一個select語句才是快照讀的地方(後續查的就是這個快照數據)
- Serializable隔離級別:快照讀會退化為當前讀
MVCC介紹
全稱Multi-Version Concurrency Control 多版本併發控制。
指的是維護一個數據的多個版本,使得讀寫操作沒有衝突。
快照讀為MYSQL實現MVCC提供了一個非阻塞讀功能,MVCC的具體實現,還需要依賴,資料庫的三個隱藏欄位、
undo log日誌、readView
MVCC-實現原理
記錄中的隱藏欄位
當我們創建了表除了自己本身創建的欄位,innoDB引擎會自動給我們創建三個欄位
分別是:
- DB_TRX_ID
- DB_ROLL_PTR
- DB_ROW_ID
隱藏欄位 | 含義 |
---|---|
DB_TRX_ID | 最近修改事務ID,記錄插入這條記錄或者最後一次修改該記錄的ID(事務id) |
DB_ROLL_PTR | 回滾指針,指向這條記錄的上一個版本,用於配合undo log指向上一個版本 |
DB_ROW_ID | 隱藏主鍵,如果表結構沒有指定主鍵,就會生成該隱藏欄位 |
可以查看表空間文件內容來查看隱藏欄位信息
事務id是自增的!
在MYSQL中提供了一個命令來查看表空間文件的記錄信息
ibd2sdi xxx.ibd
undo log版本鏈
回滾日誌,在insert、update、delete的時候產生的便於數據回滾的日誌
當insert的時候,產生的undo log日誌只在回滾時需要,在事務提交後,可被立即刪除。
當update、delete的時候,產生的undo log日誌不只是回滾時需要,在快照讀時也需要,不會被立即刪除。
Undo log版本鏈
不同事務或相同事務對同一條記錄進行修改,會導致該記錄的undo log生成一個記錄的版本鏈表,鏈表的頭部是最新的舊記錄,鏈表的尾部是最早的舊記錄。
執行順序:
從上到下代表執行順序。在同一行代表同一時間執行。
ReadView(讀視圖)
ReadView(讀視圖)是快照讀SQL執行時MVCC提取數據的依據,記錄並維護系統當前活躍的事務(未提交的)id
ReadView中包含了四個核心欄位
欄位 | 含義 |
---|---|
m_ids | 當前活躍的事務id集合 |
min_trx_id | 最小活躍的事務ID |
max_trx_id | 預分配事務ID,當前最大事務ID+1(因為事務ID是自增的) |
creator_trx_id | ReadView創建者的事務ID |
版本鏈數據訪問規則
trx_id 代表的是當前事務的id
用這個id和ReadView的四個核心欄位進行比對
-
trx_id == creator_trx_id 可以訪問該版本 這個條件成立代表數據是當前這個事務更改的
-
trx_id < min_trx_id 可以訪問該版本 這個條件成立,說明數據已提交
-
trx_id > max_trx_id 不可以訪問該版本 這個條件成立,說明事務是在ReadView生成之後才開啟的
-
min_trx_id <= trx_id <= max_trx_id 如果trx_id不在m_ids中,就可以訪問該版本
這個條件成立,說明數據已經提交。
根據隔離級別的不同ReadView生成時機不同
-
在Read Committed隔離級別下
在事務第一次執行快照讀時都生成一個Read view
-
在Repeatable read隔離級別下
在事務第一次執行快照讀時生成,後續復用這個Read view
在RC隔離級別下,版本鏈訪問原理分析
在事務第一次執行快照讀時都生成一個Read view
第一個快照讀,讀取情況
這個快照讀,根據規則,讀取的是0x00002這個地址的數據,對應著事務2修改後的數據內容。
第二個快照讀,讀取情況
這個快照讀,根據規則讀取到的是,0x00003地址的數據內容,就是事務3修改後的數據。
在RR隔離級別下,版本鏈訪問原理分析
在RR隔離級別下,只有事務在第一次執行快照讀的時候生成ReadView,後續復用這個ReadView
具體的和RC規則一致,不重覆講解。
總結
隱藏欄位+Undo log版本鏈+ReadView組成MVCC
MVCC+鎖構成事務的隔離機制
事務的一致性由Redo log和undo log共同保證