MySQL - 深度學習 - MVCC

前言

本文整理一下,MySQL在RC、RR級別下的InnoDB的非阻塞讀如何實現

什麼是MVCC

MVCC(Multi-Version Concurrency Control ,多版本併發控制)指的就是在使用READ COMMITTDREPEATABLE READ這兩種隔離級別的事務在執行普通的SELECT操作時訪問記錄的版本鏈的過程,這樣子可以使不同事務的讀-寫寫-讀操作併發執行,從而提升系統性能。

事務id什麼時候創建的?

如果某個事務執行過程中對某個表執行了增、刪、改操作,那麼InnoDB存儲引擎就會給它分配一個獨一無二的事務id,分配方式如下:

  • 對於只讀事務來說,只有在它第一次對某個用戶創建的臨時表執行增、刪、改操作時纔會爲這個事務分配一個事務id,否則的話是不分配事務id的。
  • 對於讀寫事務來說,只有在它第一次對某個表(包括用戶創建的臨時表)執行增、刪、改操作時纔會爲這個事務分配一個事務id,否則的話也是不分配事務id的。

事務id是怎麼生成的?

這個事務id本質上就是一個數字,具體策略如下:

  • 服務器會在內存中維護一個全局變量,每當需要爲某個事務分配id時,將該值分給該事務,變量值自增+1

  • 每當這個變量的值爲256的倍數時,就會將該變量的值刷新到系統表空間的頁號爲5的頁面中一個稱之爲Max Trx ID的屬性處,這個屬性佔用8個字節的存儲空間。

  • 當系統下一次重新啓動時,會將上邊提到的Max Trx ID屬性加載到內存中,將該值加上256之後賦值給我們前邊提到的全局變量(因爲在上次關機時該全局變量的值可能大於Max Trx ID屬性值)。

這樣就可以保證整個系統中分配的事務id值是一個遞增的數字。先被分配id的事務得到的是較小的事務id,後被分配id的事務得到的是較大的事務id

RC、RR隔離級別下,生成ReadView的時機

READ UNCOMMITTED不會生成ReadView,直接讀取記錄的最新版本即可。

READ COMMITTD:在每一次進行普通SELECT操作前都會生成一個ReadView。

REPEATABLE READ:只有第一次進行普通SELECT操作前生成一個ReadView,之後複用同一ReadView。

原理

對於使用InnoDB存儲引擎的表來說,它的聚簇索引記錄中都包含兩個必要的隱藏列,比如上方的 t 表

隱藏列 說明
trx_id 每次一個事務對某條聚簇索引記錄進行改動時,都會把該事務的事務id賦值給trx_id隱藏列
roll_pointer 每次對某條聚簇索引記錄進行改動時,都會把舊的版本寫入到undo日誌中,然後這個隱藏列就相當於一個指針,可以通過它來找到該記錄修改前的信息。

插入第一條記錄

INSERT INTO `t`(`number`, `account`) VALUES (1, '100');

假設插入該記錄的事務id100,那麼此刻該條記錄的示意圖如下所示:
在這裏插入圖片描述
可以看到插入了undo日誌中,insert undo 只是在事務回滾時有用,當事務提交後就沒用了,而且會被回收。

undo日誌說明

  • 主要分爲兩種日誌

    • insert undo log(只針對事務本身可見,對其他事務無影響)
    • update undo log(update/delete) 也就是我們需要重點關注的知識,看下面總結圖
  • 主要用於回滾,並維護原子性

  • 存在與數據庫中的 undo segment(段)中

  • 用於MVCC(實現非鎖定讀),讀取一行記錄時,若已被其他事務佔據,則通過undo讀取之前的版本

  • 行操作(回滾行記錄到某個版本)

    undo是邏輯日誌,只是將數據庫邏輯的恢復到執行語句或事務之前

什麼時候創建 undo日誌

每次對記錄進行改動,都會記錄一條undo日誌,每條undo日誌也都有一個roll_pointer屬性(INSERT操作對應的undo日誌沒有該屬性,因爲該記錄並沒有更早的版本),可以將這些undo日誌都連起來,串成一個鏈表。

回收 undo日誌

隨着系統的運行,在確定系統中包含最早產生的那個ReadView的事務不會再訪問某些update undo日誌以及被打了刪除標記的記錄後,有一個後臺運行的purge線程會把它們真正的刪除掉。

總結圖

真實字段是DB_ROW_ID、DB_TRX_ID、DB_ROLL_PTR,我們爲了美觀才寫成了row_id、transaction_id和roll_pointer。

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章