mysql oracle mvcc_PostgreSQL、Oracle/MySQL和SQL Server的MVCC实现原理方式
PostgreSQL、Oracle/MySQL和SQL Server的MVCC實現(xiàn)原理方式
關(guān)系數(shù)據(jù)庫管理系統(tǒng)使用MVCC(Multiversion Concurrency Control多版本并發(fā)控制)來避免寫操作堵塞讀操作的并發(fā)問題,MVCC也就是通過使用數(shù)據(jù)的多個版本保證并發(fā)讀寫不沖突的一種機制,不同的數(shù)據(jù)庫有不同的實現(xiàn),這也是數(shù)據(jù)庫系統(tǒng)讓人頭疼的地方,關(guān)系數(shù)據(jù)庫表面看上去很簡單方便,使用標準的SQL語句操作讓人很放心,但是隨著系統(tǒng)規(guī)模增加,并發(fā)用戶增加,數(shù)據(jù)庫會出現(xiàn)性能降低的現(xiàn)象,這時我們可能需要從外部的微調(diào)進入到內(nèi)部原理的深入研究,而每個數(shù)據(jù)庫內(nèi)部實現(xiàn)并發(fā)的原理都是不同的,如果我們擁有多個不同的數(shù)據(jù)庫,那么需要不同的調(diào)校方法,這時作為生產(chǎn)系統(tǒng)的核心數(shù)據(jù)庫開始變得不那么讓人放心,本文提供了市面上幾種流行數(shù)據(jù)庫的內(nèi)部MVCC不同的實現(xiàn)。
MVCC的兩種不同實現(xiàn)方式
第一種實現(xiàn)方式是將數(shù)據(jù)記錄的多個版本保存在數(shù)據(jù)庫中,當這些不同版本數(shù)據(jù)不再需要時,垃圾收集器回收這些記錄。這個方式被PostgreSQL和Firebird/Interbase采用,SQL Server使用的類似機制,所不同的是舊版本數(shù)據(jù)不是保存在數(shù)據(jù)庫中,而保存在不同于主數(shù)據(jù)庫的另外一個數(shù)據(jù)庫tempdb中/
第二種實現(xiàn)方式只在數(shù)據(jù)庫保存最新版本的數(shù)據(jù),但是會在使用undo時動態(tài)重構(gòu)舊版本數(shù)據(jù),這種方式被Oracle和MySQL/InnoDB使用。
下面看看具體數(shù)據(jù)庫實現(xiàn)機制。
PostgreSQL的MVCC
在PostgreSQL中,當一行記錄被更新時,該行數(shù)據(jù)的新版本(稱為tuple)將被創(chuàng)建并插入表中,之前版本提供一個指針指向新版本,之前版本被標記為"expired"過期,但是還保留在數(shù)據(jù)庫直到垃圾收集器回收掉。
為了支持多版本,每個tuple有以下附加數(shù)據(jù)記錄:
xmin – 插入更新記錄和創(chuàng)建這個tuple的事務的ID
xmax – 刪除記錄或創(chuàng)建這個tuple新版本或刪除記錄的事務。這個字段初始是null.
事務狀態(tài)是保存在 $Data/pg_clog的CLOG中. 這個表包含每個事務狀態(tài)信息的兩個字節(jié),可能的狀態(tài)有in-progress, committed, 或 ?aborted。 當一個事務結(jié)束后,PostgreSQL并不會將數(shù)據(jù)庫記錄的改變undo回滾的,它只是在CLOG標記事務為aborted . 一個PostgreSQL表可能包含許多這樣aborted退出事務的數(shù)據(jù)。
一個稱為Vacuum 清理進程會提供expired過期/aborted退出的記錄版本的垃圾回收,Vacuum 清理器也會刪除被垃圾回收的tuple相關(guān)的索引項。
一個tuple的xmin是有效且xmax無效時,它是可見的。 “Valid有效” 意味著 “或者是 committed 或代表當前事務”. 為了避免反復操作CLOG 表, PostgreSQL 在tuple中維持狀態(tài)標識,以表示tuple是否是“known committed” 或 “known aborted”.
Oracle的MVCC
Oracle是在回滾段(也就是‘undo log’)中保存舊版本, 一個事務ID并不是一個順序數(shù)字,而是由一系列數(shù)字組成,這些數(shù)字指向回滾段的頭部事務槽 (slot)。 回滾段能讓新事務能重用存儲,重用被已經(jīng)提交或退出的舊事務使用過的事務槽,這種自動重用機制使得Oracle使用有限的回滾段可以管理大量的事務。
回滾段的頭部塊是用作一個事務表,這里保存著事務的狀態(tài),稱為System Change Number或 SCN, Oracle并不是存儲頁面中的每個記錄的事務ID, 而是通過保存頁面中每行記錄的唯一事務ID的數(shù)組陣列節(jié)約空間使用, 只保存記錄的數(shù)組偏移量offset,和每個事務ID保存在一起的是一個指針,指向該頁事務創(chuàng)建的最后undo記錄,不僅表記錄是這種方式存儲,索引記錄也是使用同樣技術(shù),這是Oracle和PostgreSQL主要區(qū)別之一.
當一個Oracle事務啟動時,它會標記一個當前事務狀態(tài)SCN. 當讀取一個表或一個索引頁時,Oracle使用SCN數(shù)字來決定該頁是否包含不應該讓當前事務知曉的事務影響效果, Oracle通過尋找相聯(lián)的回滾段頭部來檢查該事務的狀態(tài),但是為了節(jié)約時間,第一次是真正查詢事務,查詢完成它的狀態(tài)會被記錄在該頁中以避免后來再次查詢,如果該頁被發(fā)現(xiàn)包含不可見事務的影響,Oracle通過undoing每個這樣的事務影響來重新創(chuàng)建該頁的舊版本。它掃描和每個事務有關(guān)的記錄,將這些事務效果應用到該頁,直至那些所有事務效果應用完成后被移除,以該方式創(chuàng)建的新頁再用于訪問其中的tuple。
Oracle中的記錄頭:
一個記錄頭部不會增長,總是有固定大小,對于非集群的表,記錄頭部是3個字節(jié),一個字節(jié)被用于存儲標識,一個字節(jié)用于顯示記錄是否被鎖住(比如它被更新了但是沒有確認提交committed), ,一個字節(jié)用于列計數(shù)。
SQL Server的MVCC
在SQL Server數(shù)據(jù)庫內(nèi)部使用記錄版本實現(xiàn)快照隔離和讀取提交,只有需要此項的數(shù)據(jù)庫才會必須開啟并且會產(chǎn)生相應的成本開銷。
當一個記錄被修改或刪除時,使用copy-on-write機制能夠有效地啟動版本,Row versioning–based 事務能夠有效地“view看到” 數(shù)據(jù)的從過去到現(xiàn)在的的前后一致的各種版本。
記錄版本Row version保存在版本存儲中,其駐留在主數(shù)據(jù)庫之外的tempdb數(shù)據(jù)庫中, ?更特別地,當一張表或索引中一個記錄被修改,新記錄將攜帶上執(zhí)行修改的事務的 ”sequence_number”. 記錄的舊版本將被拷貝到版本存儲中, 新記錄包含一個指針指向版本存儲中的這個舊記錄,如果多個長運行 long-running事務存在,并且需要多個 ”版本versions”, 在版本存儲中的記錄也許包含指向該記錄更早版本的指針。
SQL Server的版本存儲清除:
SQL Server自動管理版本存儲的大小,維持一個清除線程來確保版本存儲中記錄版本數(shù)量不至于太長,超過需要,對于在快照隔離下運行的查詢,版本存儲保留記錄版本直到修改數(shù)據(jù)的事務完成,并且事務包含的任何需要修改數(shù)據(jù)的語句全部完成,對于在Read Committed 快照隔離下運行的SELECT語句 ,一個特別的記錄版本就再也不需要了,一旦SELECT語句執(zhí)行完成就被移除。
如果tempdb已經(jīng)沒有空閑空間, SQL Server會調(diào)用清除功能,增加文件的大小,當然前提是假設我們配置文件是自動增長的, ?如果磁盤已經(jīng)沒有空間,文件不能自動增長, SQL Server會停止產(chǎn)生版本,如果這種情況發(fā)生,任何需要讀取版本的快照查詢因為空間限制將失敗。
SQL Server中記錄頭
4 字節(jié)
- 兩字節(jié)記錄元數(shù)據(jù)(記錄類型)
- 兩字節(jié)向前指向記錄中的NULL 位圖bitmap. 這是記錄(固定長度列)實際大小的差值offset.
版本標記Versioning tag – 這是一個14-byte結(jié)構(gòu),包含時間戳加一個指向tempdb中版本存儲的指針,這里時間戳是 trasaction_seq_number, 當需要支持一個版本操作時,加入版本信息到記錄中時的時間。
與50位技術(shù)專家面對面20年技術(shù)見證,附贈技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的mysql oracle mvcc_PostgreSQL、Oracle/MySQL和SQL Server的MVCC实现原理方式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python扫描端口脚本_Pyhton扫
- 下一篇: 解放军大办民兵师战斗力为何如此之强