日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

InnoDB 事务/锁/多版本分析?你了解多少?

發布時間:2023/12/10 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 InnoDB 事务/锁/多版本分析?你了解多少? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

? InnoDB事務

– 事務結構/功能

– XA事務/Group Commit

– mini-transaction? InnoDB鎖 – 鎖結構/類型/功能

– 鎖等待/死鎖檢測

– 自增序列鎖(autoinc lock)

– 半一致讀(semi-consistent read)

– 隱式鎖(implicit lock)

? InnoDB多版本

– ReadView

– 聚簇索引/二級索引

– 快照讀 – Index Only Scan

– RC vs RR

– Purge

? InnoDB事務/鎖/多版本總結


?InnoDB事務

– 事務結構/功能

– XA事務/Group Commit

– mini-transaction

InnoDB事務-結構

InnoDB事務-結構(cont.)

? trx_sys(全局唯一)

– mutex: critical section,控制事務的分配/提交/回滾

– max_trx_id: 當前系統最大的事務號 分配256次,寫一次文件,持久化

– trx_list: 系統當前所有活躍事務鏈表

– view_list: 系統當前所有ReadView鏈表
? trx_struct(事務對象)

– id/no: 事務號,標識事務起始/提交順序 ? id用戶可見,no用戶不可見;共用trx_sys的max_trx_id進行分配 – xid: XA事務標識 – (global)read_view: 事務所屬的ReadView

– trx_locks: 事務持有的所有lock(表鎖/記錄鎖/Autoinc鎖)

– wait_lock: 事務當前正在等待的lock

InnoDB事務-功能

?快照讀

– 創建ReadView,實現RC/RR隔離級別(MVCC時分析)
? 當前讀

– 對表/記錄加鎖

– 同一事務,所有的鎖,鏈成鏈表
? I/U/D

– 加鎖

– 記錄undo日志/redo日志
? 數據持久化

– 事務commit ? 需要哪些操作?
? 數據回滾

– 事務rollback ? 需要哪些操作?

InnoDB事務-XA事務

Why XA? – 為了保證InnoDB redo log與MySQL binlog的一致性 – backup

XA Commit流程

– InnoDBprepare -> Binlog commit -> InnoDB commit

– Binlog作為事務協調器 – Transaction Coordinator

– 參數 – MySQL:sync_binlog – InnoDB:innodb_flush_log_at_trx_commit

Group Commit – MariaDB/Percona 5.5.19-rel24/MySQL 5.6

InnoDB事務-mini-transaction

mini-transaction(微事務) – 定義 ? mini-transaction不屬于事務;InnoDB內部使用
? 對于InnoDB內所有page的訪問(I/U/D/S),都需要mini-transaction支持
– 功能 ? 訪問page,對page加latch ( 只讀訪問: S latch ;寫訪問: X latch)
? 修改page,寫redo日志 (mtr 本地緩存 )
? page操作結束,提交mini-transaction ( 非事務提交 ) – 將redo日志寫入log buffer – 將臟頁加入Flush List鏈表 – 釋放頁面上的 S/X latch
– 總結 ? mini-transaction,保證單page操作的原子性(讀/寫單一page) ? mini-transaction,保證多pages操作的原子性(索引SMO/記錄鏈出,多pages訪問的原子性)

?InnoDB鎖

– 鎖結構/類型/功能

– 鎖等待/死鎖檢測

– 自增序列鎖(autoinc lock)

– 半一致讀(semi-consistent read)

– 隱式鎖(implicit lock)

InnoDB鎖-定義

?數據庫中常用鎖類型(Lock/Latch/Mutex)

– 相同 ? 都是用來鎖住一個資源
– 不同 ? Lock (事務鎖)

– 實現復雜;功能多樣;可大量/長時間持有

– 支持死鎖檢測 – 用途:鎖用戶記錄/表
? Latch (頁面鎖)

– 實現相對簡單;功能相對簡單;少量/短時間持有

– 不支持死鎖檢測

– 用途:Latch page,防止訪問時頁面被修改/替換(pin)
? Mutex (臨界區鎖)

– 最為簡單(CAS, TAS); 功能簡單;極短持有時間

– 無死鎖檢測 – 用途:保護critical section(臨界區)

InnoDB鎖-結構

?

?lock_sys(Rec lock hash)

– InnoDB的行鎖,通過hash表管理

– hash值,通過[space, page_no]計算:同一頁面在同一hash bucket中

– 思考:表鎖呢?
? lock_struct – trx_locks: 屬于同一事務的鎖鏈表

– type_mode: 加鎖模式 ? 一個鎖對象,一個加鎖模式 – hash: 記錄鎖在hash表中的指針

– index: 鎖對應的索引 – rec_lock/tab_lock: 以上屬于表鎖/行鎖共用結構,此處為不同結構

InnoDB鎖-結構(cont.)

?lock_rec_struct

– InnoDB行鎖特殊結構
– InnoDB行鎖實例,對應于一個索引頁面中的所有記錄 n_bits = page_dir_get_n_heap(page) + LOCK_PAGE_BITMAP_MARGIN; n_bytes = 1 + n_bits / 8; lock = mem_heap_alloc(trx->lock_heap, sizeof(lock_t) + n_bytes);
– 行鎖實例的最后,是n_bytes的bitmap ? bitmap的下標對應于page中的heap_no(記錄唯一) ? bitmap=1,heap_no記錄加鎖

InnoDB鎖-行鎖

行鎖 – 行鎖實例 ? 對應 Index Page (聚簇 & 非聚簇)
– 行鎖標識 ? 記錄在page中的heap_no
– heap_no ? 記錄插入page,分配 ? 刪除記錄重用,heap_no可重用 ? heap_no與slot_no不同 ? heap_no不可用來查找記錄
– 行鎖實例(右圖) ? 根據查詢條件,行鎖實例bitmap 的1,3,6 bits設置為1,對應于 heap_no 1,3,6號記錄

InnoDB鎖-行鎖開銷

?鎖開銷接近Oracle? InnoDB 宣稱自己的行鎖代價接近于 Oracle ,一條記錄用 1 bit 即可,實 際情況呢? InnoDB 的行鎖對象,管理一個 Page ,行鎖上的 1 bit ,對應 Page 中的一條記錄。一個 400 條記錄的 Page ,一個行鎖對象大小約為 102 bytes 。
鎖一行 :
代價 為 102 bytes/ 行 ;
鎖 400 行 :
代價 為 102 bytes/400 = 2 bits/ 行。
? 實際情況 – 鎖一行代價巨大(如何優化,后續揭曉) – 鎖一頁代價較小

InnoDB鎖-鎖模式

?數據鎖模式

– 數據鎖:僅僅鎖住數據

LOCK_IS, LOCK_S, LOCK_IX, LOCK_X
– 意向鎖:LOCK_IS, LOCK_IX ? 表級鎖;加記錄鎖前必須先加意向鎖; ? 功能: 杜絕行鎖與表鎖相互等待

?非數據鎖模式

– 不鎖數據,標識數據前GAP的加鎖情況;非數據鎖與數據鎖之間不沖突
– LOCK_ORDINARY ? next key鎖,同時鎖住記錄(數據),并且鎖住記錄前面的Gap
– LOCK_GAP ? Gap鎖,不鎖記錄,僅僅記錄前面的Gap
– LOCK_NOT_GAP ? 非Gap鎖,鎖數據,不鎖Gap
– LOCK_INSERT_INTENSION ? Insert操作,若Insert的位置的下一項上已經有Gap鎖, 則獲取insert_intension鎖,等待Gap鎖釋放
– LOCK_WAIT ? 當前鎖不能立即獲取,需要等待

– 非數據鎖兼容模式

InnoDB鎖-實例分析

?

InnoDB鎖-加鎖總結

InnoDB鎖-等待

InnoDB鎖-死鎖檢測

死鎖檢測 – 加鎖需要等待,則觸發死鎖檢測
– 死鎖檢測由用戶線程處理
– 構造Wait-For-Graph (WFG)
– 深度優先遍歷 (遞歸) ? 后續改為非遞歸實現(棧)
– 死鎖檢測過程中,持有kernel_mutex ? 后續MySQL版本中,新增lock_sys->mutex
– 根據事務權重,選擇犧牲者 ? 事務權重:undo日志量 + 鎖數量

InnoDB鎖-分裂/合并/遷移

?鎖分裂 – 索引頁面分裂 -> 鎖分裂
? 鎖合并 – 索引頁面合并 -> 鎖合并
? 鎖遷移 – 插入記錄 ? Gap鎖從插入后項遷移到新插入項
– 刪除記錄 ? Gap鎖從刪除項遷移到刪除后項

InnoDB鎖-Autoinc鎖

自增序列鎖(Autoinc Lock) – 功能 ? 復雜insert語句+statement binlog下,保證master-slave一致性
– 自增序列并發控制 ? mutex: 簡單Insert/replace語句 ? Autoinc_lock: insert into select * from 語句
– 參數設置 ? innodb_autoinc_lock_mode – 0,1,2

InnoDB鎖-半一致讀

Semi-Consistent Read(半一致讀) – 目標 ? 提高系統并發性能,減少鎖等待
– 方案 ? 當前讀,可讀取記錄歷史版本 ? 不滿足查詢條件的記錄,可提前放鎖
– 前提 ? Read Committed隔離級別 ? innodb_locks_unsafe_for_binlog

InnoDB鎖-隱式鎖

Implict Lock(隱式鎖)

– 目標 ? 減少Insert時加鎖開銷,減少鎖內存消耗 ? 降低鎖一行記錄的情況( 鎖一行代價巨大 )
– 方案 ? Insert時,不加鎖(Implict lock) ? 后續scan(當前讀),如果碰到Implicit lock,則轉換為Explicit lock ? 延遲加鎖
– Implicit Lock判斷 ? 聚簇索引 – 根據記錄上的trx_id判斷(trx_id 是否為活躍事務? ) ? 二級索引 – 根據索引頁面上的max_trx_id + 回聚簇索引判斷 (max_trx_id 是否小于最小活躍事務? )

– 存在bug

InnoDB多版本

– ReadView

– 聚簇索引/二級索引

– 快照讀

– Index Only Scan

– RC vs RR

– Purge

InnoDB多版本定義

一 條語句,能夠 看到 ( 快照讀 ) 本 語句開始時 (RC)/ 本 事務開始時 (RR) 已 經提交的 其他事務所做的修改
– 快照讀 ? 讀記錄歷史版本,而非當前更新未提交版本 ? 無需加鎖,lock free ? 語句級(RC):語句開始時的快照 – 語句級ReadView ? 事務級(RR):事務開始時的快照 – 事務級ReadView
– 看到? ? 已提交的Insert/Update后項,可見并返回 ? 已提交的Delete/Update前項,可見并略過

? ReadView
所謂 ReadView ,是一個事務的集合,這些事務在 ReadView 創建時是 活躍的 ( 未提交 / 回滾 )

?read_view_struct – low_limit_no ? 提交時間早于此值(trx->no < low_limit_no)的事務,可以被purge線程回收 ? low_limit_no= trx_sys->max_trx_id
– low_limit_id ? >= 此值(trx->id >= low_limit_id)的事務,當前ReadView均不可見 ? low_limit_id= trx_sys->max_trx_id
– up_limit_id ? < 此值(trx->id < up_limit_id)的事務,當前ReadView一定可見 ? up_limit_id= ReadView創建時系統中最小活躍事務ID
– trx_ids[] ? 系統中所有活躍事務id組成的數組
? 創建ReadView

– 獲取kernel_mutex ? 遍歷trx_sys的trx_list鏈表,獲取所有活躍事務,創建ReadView

– Read Committed ? 語句開始,創建ReadView

– Repeatable Read ? 事務開始,創建ReadView

?ReadView創建

RC VS RR

InnoDB多版本-記錄組織

聚簇索引記錄 – DB_TRX_ID ? 生成此記錄的事務ID

– DB_ROLL_PTR ? 此記錄歷史版本的指針

– Delete_Bit(未給出)
? 二級索引記錄

– Delete_Bit – 索引頁面,有DB_MAX_ID ? 標識修改索引頁面的最大事務ID

InnoDB多版本-更新

?目的

– 測試各種更新場景下,聚簇索引記錄/二級索引記錄的變化
? 準備 create table test (id int primary key, comment char(50)) engine=innodb; create index test_idx on test(comment);
insert into test values (1, ‘aaa’); insert into test values (2, ‘bbb’);

更新主鍵

update test set id = 9 where id = 1;

– 舊記錄標識為刪除

– 插入一條新紀錄

– 新舊記錄前項均進入回滾段

更新非主鍵

update test set comment = ‘ccc’ where id = 9;

?InnoDB更新總結
– 更新主鍵,聚簇索引/二級索引均無法進行in place update,均會產生 兩個版本
– 更新非主鍵,聚簇索引可以in place update;二級索引產生兩個版本
– 聚簇索引記錄undo,二級索引不記錄undo
– 更新聚簇索引,記錄舊版本會進入Rollback Segment Undo Page
– 更新二級索引,同時需要判斷是否修改索引頁面的MAX_TRX_ID
– 屬于同一事務的undo記錄,在undo page中保存逆向指針

InnoDB多版本-可見性

InnoDB多版本-Cluster Index Scan

聚簇索引掃描

– 當前讀 ? 加鎖;讀取記錄最新版本 ? 通過記錄的DB_TRX_ID判斷 是否存在Implicit lock
– 快照讀 ? 不加鎖; ? 根據ReadView讀取可見版本
– Index Only Scan ? 一定為Index Only Scan

?二級索引掃描

– 當前讀 ? 加鎖(二級索引/聚簇索引) ? 讀取記錄最新版本 ? 通過page上的MAX_TRX_ID判斷 是否可能存在Implicit lock
– 快照讀 ? 不加鎖 ? 讀取記錄唯一可見版本 – 如何過濾同一記錄的不同版本?
– Index Only Scan ? cont.

?Index Only Scan

– 當前讀 ? 不能進行Index Only Scan – 當前讀需要對聚簇索引記錄加鎖 – 當前讀需要訪問聚簇索引,讀取記錄所有列
– 快照讀 ? 訪問索引不存在的列

– 不能進Index Only Scan
? 僅僅訪問索引列

– 二級索引page的MAX_TRX_ID不可見-> 不能進行Index Only Scan ? 此概率較小

– MAX_TRX_ID可見 -> 可進行Index Only Scan ? 此概率極大

InnoDB多版本-實例講解

MySQL Bugs 65745 UPDATE on InnoDB table enters recursion, eats all disk space

原因分析

– 更新主鍵字段,二級索引同樣會產生Halloween問題

?Purge

– 功能 ? 回收索引頁面中被刪除 且不會被其他事務看到的項
– 實現流程 ? 拷貝trx_sys ReadView鏈表中最老 的read_view,作為purge_read_view
? 遍歷InnoDB系統中所有的Rollback Segment, 取出最老的提交事務
? 若purge_read_view.low_limit_no > old_trx.no; 說明對應的事務可以被purge
? 反向遍歷事務的undo日志, 構造索引記錄,查詢并刪除
– 參數/優化 ? innodb_max_purge_lag() ? innodb_purge_threads (since MySQL 5.6.2)

? InnoDB事務/鎖/多版本總結

?RR vs RC

– Read Committed ? 優勢

– 高并發,低鎖開銷:semi-consistent read – no gap lock;early unlock ? 劣勢

– 不支持statement binlog – 語句級快照讀:每條語句,新建ReadView
– Repeatable Read ? 優勢 – 支持gap lock;statement binlog – 事務級快照讀:一個事務,對應一個ReadView ? 劣勢 – 并發沖突高,加鎖沖突更為劇烈 – 不支持semi-consistent read;不支持early unlock

事務Commit流程 – prepare ? 將redo日志從log buffer寫入log file,并flush – innodb_flush_log_at_trx_commit
– commit ? 處理事務產生的undo pages – insert undo pages直接回收 – 獲取事務的trx->no (標識提交順序) – update undo pages鏈入history list,等待purge
? 釋放事務持有的鎖 – 喚醒必要的等待者
? 關閉事務的read_view
? 將redo日志寫出,并flush – innodb_flush_log_at_trx_commit

事務Rollback流程 – 反向遍歷undo日志并應用 ? undo操作需要記錄redo (undo的補償日志)
– 以下流程,與commit一致 ? 處理事務產生的undo pages
? 釋放事務鎖
? 關閉read_view
? 將redo日志寫出,并flush

?

?

?

?

?

總結

以上是生活随笔為你收集整理的InnoDB 事务/锁/多版本分析?你了解多少?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。