Oracle一致性讀(Consistent Read)的原理
在Oracle資料庫中,undo主要有三大作用:
提供一致性讀(Consistent Read)、回滾事務(Rollback Transaction)以及例項恢復(Instance Recovery) 。
一致性讀是相對於髒讀(Dirty
Read)而言的。假設某個表T中有10000條記錄,獲取所有記錄需要15分鐘時間。當前時間為9點整,某使用者A發出一條查詢語句:select *
from
T,該語句在9點15分時執行完畢。當使用者A執行該SQL語句到9點10分的時候,另外一個使用者B發出了一條delete命令,將T表中的最後一條記錄刪
除並提交了。那麼到9點15分時,A使用者將返回多少條記錄?
如果返回9999條記錄,則說明發生了髒讀;如果仍然返回10000條記錄,則說明發生了一致性讀。很明顯,在 9點鐘那個時間點發出查詢語句時,表T中確實有10000條記錄,只不過由於I/O的相對較慢,所以才會花15分鐘完成所有記錄的檢索。
對於Oracle 資料庫來說,沒有辦法實現髒讀,必須提供一致性讀,並且該一致性讀是在沒有阻塞使用者的DML的前提下實現的。
那麼undo資料是如何實現一致性讀的呢?
還是針對上面的例子。使用者A在9點發出查詢語句時,伺服器程式會將9
點那個時間點上的SCN號記錄下來,假設該SCN號為SCN9.00。那麼9點整的時刻的SCN9.00一定大於等於記錄在所有資料塊頭部的ITL槽中的
SCN號(如果有多個ITL槽,則為其中最大的那個SCN號)。
注:
ITL (
Interested Transaction List)
是
Oracle資料塊內部的一個組成部分,用來記錄該塊所有發生的事務,一個itl可以看作是一個記錄,在一個時間,可以記錄一個事務(包括提交或者未提交
事務)。當然,如果這個事務已經提交,那麼這個itl的位置就可以被反覆使用了,因為itl類似記錄,所以,有的時候也叫itl槽位。
伺服器程式在掃描表T的資料塊時,會把掃描到的資料塊頭部的ITL槽中的SCN號與SCN9:00之間進行比較,哪個更大。如果資料塊頭部的SCN號比
SCN9.00要小,則說明該資料塊在9點以後沒有被更新,可以直接讀取其中的資料;否則,如果資料塊ITL槽的SCN號比SCN9.00要大,則說明該
資料塊在9點以後被更新了,該塊裡的資料已經不是9點那個時間點的資料了,於是要藉助undo塊。
9點10分,B使用者更新了表T的最後一條記錄並提交(注意,在這裡,提交或者不提交併不是關鍵,只要使用者B更新了表T,使用者A就會去讀undo資料塊)。
假設被更新記錄屬於N號資料塊。那麼這個時候N號資料塊頭部的ITL槽的SCN號就被改為SCN9.10。當伺服器程式掃描到被更新的資料塊(也就是N號
塊)時,發現其ITL槽中的SCN9.10大於發出查詢時的SCN9.00,說明該資料塊在9點以後被更新了。於是伺服器程式到N號塊的頭部,找到
SCN9.10所在的ITL槽。由於ITL槽中記錄了對應的undo塊的地址,於是根據該地址找到undo塊,將
undo塊中的被修改前的資料取出,再結合N號塊裡的資料行,從而構建出9點10分被更新之前的那個時間點的資料塊內容,這樣的資料塊叫做CR塊
(Consistent
Read)。對於delete來說,其undo資訊就是insert,也就是說該構建出來的CR塊中就插入了被刪除的那條記錄。隨後,伺服器程式掃描該
CR塊,從而返回正確的10000條記錄。
讓我們繼續把問題複雜化。假設在9點10分B使用者刪除了最後一條記錄並提交以後,緊跟著9點11分,C使用者在同一個資料塊裡(也就是N號塊)插入了2條記
錄。這個時候Oracle又是如何實現一致性讀的呢(假設表T的initrans為1,也就是隻有一個ITL
槽)?因為我們已經知道,事務需要使用ITL槽,只要該事務提交或回滾,該ITL槽就能夠被重用。換句話說,該ITL槽裡記錄的已經是SCN9.11,而
不是SCN9.10了。這時,ITL槽被覆蓋了,Oracle的伺服器程式又怎能找回最初的資料呢?
其中的祕密就在於,Oracle在記錄undo資料的時候,不僅記錄了改變前的資料,還記錄了改變前的資料所在的資料塊頭部的ITL資訊。因此,9點10
分B使用者刪除記錄時(位於N號塊裡,並假設該N號塊的ITL資訊為[Undo_block0 /
SCN8.50]),則Oracle會將改變前的資料(也就是insert)放到undo塊(假設該undo塊地址為Undo_block1)裡,同時在
該undo塊裡記錄刪除前ITL槽的資訊(也就是[Undo_block0 / SCN8.50])。刪除記錄以後,該N號塊的ITL資訊變為
[Undo_block1 /
SCN9.10];到了9點11分,C使用者又在N號塊裡插入了兩條記錄,則Oracle將插入前的資料(也就是delete兩條記錄)放到undo塊(假
設該undo塊的地址為Undo_block2)裡,並將9點11分時的ITL槽的資訊(也就是[Undo_block1 /
SCN9.10])也記錄到該undo塊裡。插入兩條記錄以後,該N號塊的ITL槽的資訊改為 [Undo_block2 / SCN9.11]。
那麼當執行查詢的伺服器程式掃描到N號塊時,發現SCN9.11大於SCN9.00,於是到ITL槽中指定的
Undo_block2處找到該undo塊。發現該undo塊裡記錄的ITL資訊為[Undo_block1 /
SCN9.10],其中的SCN9.10仍然大於SCN9.00,於是伺服器程式繼續根據ITL中記錄的Undo_block1,找到該undo塊。發現
該undo塊裡記錄的ITL資訊為[Undo_block0 /
SCN8.50],這時ITL裡的SCN8.50小於發出查詢時的SCN9.00,說明這時undo塊包含合適的undo資訊,於是伺服器程式不再找下
去,而是將N號塊、Undo_block2以及Undo_block1的資料結合起來,構建CR塊。將當前N號的資料複製到CR塊裡,然後在CR塊裡先回
退9點11分的事務,也就是在CR塊裡刪除兩條記錄,然後再回退9點10分的事務,也就是在CR塊裡插入被刪除的記錄,從而構建出9點鐘時的資料。
Oracle就是這樣,以層層巢狀的方式,查詢整個undo塊的連結串列,直到發現ITL槽裡的SCN號小於等於發出查詢時的那個SCN號為止。正常來說,當
前undo塊裡記錄的SCN號要比上一個undo塊裡記錄的SCN號要小。
但是在查詢的過程中,可能會發現當前undo塊裡記錄的ITL槽的SCN號比上一個undo塊裡記錄的SCN號還要大。這種情況說明由於事務被提交或回
滾,導致當前找到的undo塊裡的資料已經被其他事務覆蓋了,於是我們無法再找出小於等於發出查詢時的那個時間點的SCN號,這時Oracle就會丟擲一
個非常經典的錯誤——ORA-1555,也就是snapshot too old的錯誤。
以上的描述可以用圖來描述:
回滾事務 則是在執行DML以後,發出rollback命令撤銷DML所作的變化。Oracle利用記錄在ITL槽裡記錄的undo 塊的地址找到該undo塊,然後從中取出變化前的值,並放入資料塊中,從而對事務所作的變化進行回滾。
例項恢復
則是在SMON程式完成前滾並開啟資料庫以 後發生。SMON程式會去檢視undo segment頭部(所謂頭部就是undo
segment裡的第一個資料塊)記錄的事務表(每個事務在使用undo塊時,首先要在該undo塊所在的undo
segment的頭部記錄一個條目,該條目裡記錄了該事務相關的資訊,其中包括是否提交等),將其中既沒有提交也沒有回滾,而是在例項崩潰時被異常終止的
事務全部回滾。
整理自: http://blog.chinaunix.net/u3/107027/showart.php?id=2188339
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69994536/viewspace-2779197/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- db block gets 與 consistent read getsBloC
- consistent hash 原理,優化及實現優化
- Oracle一致性讀(consistents gets)Oracle
- Oracle 11g 新特性:只讀表(Read-only)Oracle
- Oracle:db file scattered readOracle
- mysql snapshot read快照讀及current read當前讀與鎖lock之一MySql
- JAVA中read()是如何讀取字元的、read()的返回值為什麼要賦給整型變數?配合available讀取字長時它們的工作原理是什麼?Java字元變數AI
- MySQL事務(二)事務隔離的實現原理:一致性讀MySql
- MySQL半一致性讀原理解析-從原始碼角度解析MySql原始碼
- Oracle direct path read相關隱含引數Oracle
- 一致性Hash的原理與實現
- 05 Shell read讀取控制檯輸入
- Oracle 的Lgwr Worker的工作原理Oracle
- 【TUNE_ORACLE】等待事件之IO等待“read by other session”Oracle事件Session
- 【TUNE_ORACLE】等待事件之IO等待“direct path read”Oracle事件
- python中讀取檔案的read、readline、readlines方法區別Python
- Reading Face, Read Health論文閱讀筆記筆記
- oracle的只讀事務Oracle
- 讀寫一致性的一些思考
- 【TUNE_ORACLE】等待事件之IO等待“db file scattered read”Oracle事件
- 【TUNE_ORACLE】等待事件之IO等待“db file sequential read”Oracle事件
- 深入淺出一致性Hash原理
- 等待事件db file sequential read、db file scattered read和direct read的區別事件
- 深入解讀Quartz的原理quartz
- MySQL e二級索引上的一致性讀MySql索引
- 如何解讀Oracle的LOAD PROFILEOracle
- MySQL的repeatable readMySql
- Mysql的read_only 只讀屬性說明 (運維筆記)MySql運維筆記
- Oracle的資料併發與一致性詳解(上)Oracle
- 閱讀器關閉時嘗試呼叫 Read 無效。
- Oracle DRM原理介紹Oracle
- 強一致性hash實現java版本及強一致性hash原理Java
- 一文搞懂一致性hash的原理和實現
- 一文搞懂一致性 hash 的原理和實現
- direct path read/read temp等待事件事件
- 對Mysql中的read_only 只讀屬性做簡要說明MySql
- oracle聯機熱備份的原理(轉)Oracle
- Promise原理解讀Promise