ORACLE的工作機制-2

junsansi發表於2007-08-09

ORACLE的工作機制-2 (by xyf_tck)

生成編譯程式碼之後,接著下一步伺服器程式要準備開始更新資料,伺服器程式將到DB BUFFER中查詢是否有相關物件的快取資料,下面分兩個可能進行解釋:

如果沒有,伺服器程式將在表頭部請求一些行鎖,如果成功加鎖,伺服器程式將從資料檔案中讀入這些行所在的第一個資料塊(db block)DB BLOCKORACLE的最小操作單元,即使你想要的資料只是DB BLOCK中很多行中的一行或幾行,ORACLE也會把這個DB BLOCK中的所有行都讀入DB BUFFER中)放入DB BUFFER中空閒的區域或者覆蓋已被擠出LRU列表的非髒資料塊緩衝區,並且排列在LRU列表的頭部,如果這些非髒資料緩衝區寫完也不能滿足新資料的請求時,會立即觸發DBWN程式將髒資料列表中指向的緩衝塊寫入資料檔案,並且清洗掉這些緩衝區,來騰出空間緩衝新讀入的資料,也就是在放入DB BUFFER之前也是要先申請DB BUFFER中的鎖存器,成功鎖定後,再寫入DB BUFFER,然後把這個塊的頭部事務列表及SCN資訊及被影響的行資料原值寫入回滾段中,以便ORACLEROLLBACK時可以利用當前資料塊和回滾段重構資料塊的"前映像"或遞迴重構出"前…前映像"來實現讀一致性。(回滾段可以儲存在專門的回滾表空間中,這個表空間由一個或多個物理檔案組成,並專用於回滾表空間,回滾段也可在其它表空間中的資料檔案中開闢。)然後在LOG BUFFER中生成日誌,伺服器程將該語句影響的被讀入DB BUFFER塊中的這些行的ROWID及將要更新的原值和新值及SCN等資訊,以及回滾段的修改資訊(即對某某回滾段地址進行了什麼修改)逐條的寫入REDO LOG BUFFER,在寫入REDO LOG BUFFER之前也是先請求REDO LOG BUFFER塊的鎖存器,成功鎖定之後才開始把REDOLOG寫入REDOLOG BUFFER。當寫入達到REDO LOG BUFFER大小的三分之一或寫入量達到1M或超過三秒後或發生檢查點時或者COMMIT時或者DBWN之前觸發LGWR程式,LGWR將把REDO LOG BUFFER中的資料寫入磁碟上的重做日誌檔案,已被寫入重做日誌檔案的REDO LOG BUFFER中的塊上的鎖存器被釋放,並可被後來寫入的資訊所覆蓋。回滾段其實也有BUFFER(在DB BUFFER中開闢),回滾段BUFFER中的內容是最早向磁碟上回滾段中寫的,寫完這些才會生成日誌BUFFER中的內容,原因是日誌中必須要記錄回滾段的新舊變化以便在恢復時從日誌中的記錄的回滾段新舊變化對回滾段再次重寫,記住,REDO光是對資料檔案依據日誌檔案重寫,也要依據日誌檔案對回滾段重寫,而且重寫回滾段要先於重寫資料檔案,要理解REDO就是重來一遍,所謂重來一遍就要跟正常的先後順利一樣重做一遍(正常的操作中的順序就是先讀入DB BUFFER寫回滾段buffer,後寫回滾段,後寫日誌BUFFER,後改寫DB BUFFER,後寫日誌最後寫資料檔案)區別是REDO時不用再記日誌了,這樣解釋後相信大家應該理解為什麼日誌中也必須要記錄回滾段的資訊了,只有這樣才可以對正常操作中的一個ROLLBACK動作進行恢復,即在REDO過程中利用即時重寫的資料塊和回滾段重構出一個當時適用的前映象來rollback。當一個重做日誌檔案寫滿後,LGWR將切換到下一個重做日誌檔案,重做日誌檔案也是迴圈工作方式。如果是歸檔模式,歸檔程式還將前一個寫滿的重做日誌程式寫入歸檔日誌檔案。當DB BUFFER改寫之後,伺服器程式在髒資料列表中建立一條指向此DB BUFFER緩衝塊的指標。接著伺服器程式會從資料檔案讀入第二個資料塊(db block)重複以上讀入,建立回滾段,寫LOG BUFFER,改寫DB BUFFER,放入髒列表的動作,當髒資料列表達到一定長度時,DBWN程式將髒資料列表中指向的緩衝塊全部寫入資料檔案,也就是釋放加在這些DB BUFER塊上的鎖存器,並在修改相應塊的頭部的SCN號(一次UPDATE操作只對應一個SCN)。前面說過DBWN動作之前會先觸發LGWR,這用以確保寫入資料檔案的改變首先會被記錄在日誌檔案中。實際上ORACLE可以從資料檔案中一次讀入多個塊放入DB BUFFER,然後再對這些塊建回滾段、再記日誌等等,也就是每次操作的物件是DB BLOCK的複數,而不僅限於一次操作一個DB BLOCK,可以通過引數DB_FILE_MULTIBLOCK_READ_COUNT來設定一次讀入的塊的個數。注意,不管是否提交,使用者的所有更改都會被記錄在日誌檔案中,使用者級回滾的動作(rollback)沒有對應的COMMIT SCN。在密集事務的情況下,LGWR可以把多個COMMIT產生的REDO條目批量寫入REDO LOG FILE,但每個COMMIT之間有十分之一秒的間隔,且會產生不同的COMMIT SCN。LGWR正常情況下是一個休眠程式,會被一定的條件觸發,喚醒,比如COMMIT就是一個喚醒條件,一旦LGWR被喚醒,LGWR將把喚醒時間點之前LOG BUFFER中產生的所有內容(從上次LGWR喚醒後到本次喚醒前之間寫入LOG BUFFER的內容)寫入LOG FILE,直到LGWR完成後,LGWR才可以被再次觸發,在LGWR觸發到完成期間所有對資料庫的操作仍然可以不間斷的加入LOG BUFFER。在這段時間內,LGWR不再接收其它條件的觸發,比如緊跟前一個COMMIT之後的其它COMMIT(複數)都要等待LGWR完成後才可以再次觸發LGWR,並在LGWR下次被觸發時,將積累的REDO BUFFER條目一次性寫入REDO LOG,後繼的COMMIT不會單個單個的觸發LGWR

如果要查詢的資料已快取,則根據使用者的SQL操作型別決定如何操作,如果是SELECT則檢視DB BUFFER塊的頭部是否有事務,如果有,將利用回滾段進行重構出一致性塊再讀取,如果沒有則比較SELECTSCNDB BUFFER塊頭部的SCN如果比自己大,仍然同上,如果比自己小則認這是一個非髒快取,可以直接從這個DB BUFFER塊中讀取。如果是UPDATE則即使在DB BUFFER中找到一個沒有事務,而且SCN比自己小的非髒快取資料塊,伺服器程式仍然要到表的頭部對這條記錄申請加鎖,加鎖成功則進行後續動作,如果不成功,則要等待前面的程式解鎖後才能進行動作。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/7607759/viewspace-22273/,如需轉載,請註明出處,否則將追究法律責任。

相關文章