程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> Oracle數據庫 >> Oracle教程 >> PostgreSQL、Oracle/MySQL和SQL Server的MVCC實現原理方式

PostgreSQL、Oracle/MySQL和SQL Server的MVCC實現原理方式

編輯:Oracle教程

PostgreSQL、Oracle/MySQL和SQL Server的MVCC實現原理方式


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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved