ORACLE的工作機制-4

junsansi發表於2007-08-09

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

在這裡我們要說一下回滾段儲存的資料,假如是delete操作,則回滾段將會記錄整個行的資料,假如是update,則回滾段只記錄行被修改了的欄位的變化前的資料(前映像),也就是沒有被修改的欄位是不會被記錄的,假如是insert,則回滾段只記錄插入記錄的rowid。這樣假如事務提交,那回滾段中簡單標記該事務已經提交;假如是回退,則如果操作是delete,回退的時候把回滾段中資料重新寫回資料塊,操作如果是update,則把變化前資料修改回去,操作如果是insert,則根據記錄的rowid把該記錄刪除。注意,檢查點除了觸發LGWR和DBWN向資料塊頭部寫SCN和COMMIT SCN,檢查點還向控制檔案和資料檔案頭部寫SCN,而使用者的DML和COMMIT僅是向資料塊頭部寫SCN和COMMIT SCN而不更新控制檔案和資料檔案的SCN,SMON的前滾是以檔案頭部的SCN為起始點的也就是從前一個檢查點開始,SMON的回滾是回滾所有回滾段中未標識為已提交的資料塊,使用者的回滾是回滾與此事務有關的回滾段中未標識為已提交的資料塊。下面我們要講DBWN如何來寫資料檔案,在寫資料檔案前首先要找到可寫的空閒資料塊, ORACLE中空閒資料塊可以通過FREELIST或BITMAP來維護,它們位於一個段的頭部用來標識當前段中哪些資料塊可以進行INSERT。在本地管理表空間中ORACLE自動管理分配給段的區的大小,只在本地管理的表空間中才能選用段自動管理,採用自動段空間管理的本地管理表空間中的段中的空閒資料塊的資訊就存放在段中某些區的頭部,使用點陣圖來管理(最普通的情況是一個段的第一個區的第一個塊為FIRST LEVEL BITMAP BLOCK,第二個塊為SECOND LEVEL BITMAP BLOCK,第三個塊為PAGETABLE SEGMENT HEADER,再下面的塊為記錄資料的資料塊,FIRST LEVEL BITMAP BLOCK的父資料塊地址指向SECOND LEVEL BITMAP BLOCK,SECOND LEVEL BITMAP BLOCK的父資料塊地址指向PAGETABLE SEGMENT HEADER,FIRST LEVEL BITMAP BLOCK記錄了它所管理的所有塊(包括頭部三個塊,不僅僅指資料塊)的狀態,標識的狀態有Metadata、75-100% free、50-75% free、25-50% free、0-25% free、full、unformatted,在SECOND LEVEL BITMAP BLOCK中有一個列表,記錄了它管理的FIRST LEVEL BITMAP BLOCK,PAGETABLE SEGMENT HEADER中記錄的內容比較多,除了記錄了它管理的SECOND LEVEL BITMAP BLOCK,還記錄了各個區的首塊地址以及各個區的DB BLOCK的個數,段的各個區所對應的FIRST LEVEL BITMAP BLOCK的塊地址以及區裡面記錄資料的資料塊的起始地址。如果一個區擁有很多塊,這時會在一個區裡出現兩個或多個FIRST LEVEL BITMAP BLOCK,這些FIRST LEVEL BITMAP BLOCK分別管理一個區中的一些塊,當區的資料塊比較少時,一個區的FIRST LEVEL BITMAP BLOCK可以跨區管理多個區的資料塊,BITMAP BOLCK最多為三級)。採用手動管理的本地管理表空間中的段和資料字典管理的表空間中的段中的空閒資料塊的管理都使用位於段頭部的空閒列表來管理,例如SYSTEM表空間是本地管理表空間,但是它是採用了手動段空間管理,所以也是用FREELIST來管理段中的空閒資料塊的。空閒列表是一個邏輯上的連結串列,在段的HEADER BLOCK中記錄了一個指向第一個空閒塊的BLOCK ADDRESS,第一個DB BLOCK中同時也記錄了指向下一個空閒塊的BLOCK ADDRESS。以此形成一個單向連結串列。如果段上有兩個FREE LIST則會在段頭部的HEADER BLOCK存有兩個指標分別指向兩個空閒塊並建立獨立的兩個單向連結串列。空閒列表的工作方式:首先當建立一個段時,初始分配的第一個區的第一個塊會成為段的頭塊,初始分配的第一個區的其它塊將全部加入空閒列表,再次擴充套件一個區時,這個區中的塊立即全部加入空閒列表,擴充套件一次加入一次。與點陣圖管理不同的是用空閒列表時區的頭部將不記錄區裡面空閒塊的資訊。當其中空閒空間小於PCTFREE設定的值之後,這個塊從空閒列表刪除,即上一個指向它的塊中記錄的下一個空閒塊地址更改為其它空閒塊的地址,使得這個塊類似於被短路,當這個塊中的內容降至PCTUSED設定的值之下後,這個資料塊被再次加入空閒列表,而且是加入到空閒列表前端,即頭塊直接指向它,它再指向原頭塊指向的空閒塊,位於空閒列表中的資料塊都是可以向其中INSERT的塊,但是INSERT都是從空閒列表指向的第一個塊開始插入,當一個塊移出了空閒列表,但只要其中還有保留空間就可以進行UPDATE,當對其中一行UPDATE一個大資料時,如果當前塊不能完全放下整個行,只會把整個行遷移到一個新的資料塊,並在原塊位置留下一個指向新塊的指標,這叫行遷移。如果一個資料塊可以INSERT,當插入一個當前塊裝不下的行時,這個行會溢位到兩個或兩個几上的塊中,這叫行連結。如果使用者的動作是INSERT則伺服器程式會先鎖定FREELIST,然後找到第一個空閒塊的地址,再釋放FREELIST,當多個伺服器程式同時想要鎖定FREELIST時即發生FREELIST的爭用,也就是說多個程式只在同時INSERT時才會發生FREELIST爭用,可以在非採用自動段空間管理的表空間中建立表時指定FREELIST的個數,預設為1,如果是在採用自動段空間管理的表空間中建立表,即使指定了FREELIST也會被忽略,因為此時將使用BITMAP而不是FREELIST來管理段中的空閒空間。採用自動段空間管理還會忽略的引數有PCTUSED和FREELIST GROUPS。如果使用者動作是UPDATE或DELETE等其它操作,伺服器程式將不會使用到FREELIST和BITMAP,因為不要去尋找一個空閒塊,而使用鎖的佇列。對資料塊中資料操作必須使用transaction entries,即事務入口。在建立段時我們可以通過MINTRANS和MAXTRANS引數指定它的最大值和最小值,MAXTRANS規定了在段中每一個塊上最大併發事務數量,可以輸入1到255之間的值。我們可以把它比喻為是一些長在塊頭部的事務插座,每個插座後面是一個可以伸縮的操作手,當事務程式插到一個插座上時相當於找到一個可以運算元據塊中資料行的操作手,通過這個操作手,事務程式可以對塊中資料進行INSERT、UPDATE、DELETE等操作。在沒有超過MAXTRANS設定的最大值時,如果transaction entries不夠用,則會在塊上自動分配一個,但不會影響其它塊中的transaction entries數量。只不過INSERT操作必須要先找到空閒塊然後才能INSERT。那麼DBWN是根據什麼順序來寫DB BUFFER中的髒資料的呢?ORACLE從8I開始加入新的資料結構--檢查點佇列(Buffer Checkpoint Queue)。檢查點佇列是一個連結佇列。這個佇列的按照Buffer塊第一次被修改的順序排列,分別指向被修改的Buffer塊。在DB_Buffer中的資料被第一次被修改時,會記錄所生成的REDO LOG條目的位置RBA作為該Buffer的Low RBA,記錄在該Buffer的頭部(Buffer Header),如果該資料繼續被修改,則把該塊修改的最新的REDO LOG的RBA作為High RBA記錄在該Buffer的頭部。如果DB_Buffer中的塊沒有被修改的資料,則該塊的頭部不會有Low RBA和High RBA的資訊。檢查點佇列按照被修改塊的Low RBA的遞增值連結修改塊,沒有被修改的塊因為沒有Low RBA,而不會加入到檢查點佇列中。在沒有檢查點發生時DBWR就按照檢查點佇列的Low RBA的升序,將被修改的塊寫入到資料檔案中。當塊被寫入到資料檔案後,該塊會從檢查點佇列中斷開。DBWR繼續寫下一個塊。CKPT程式每三秒記錄檢查點佇列中對應的最小Low RBA到控制檔案中,也就是更新控制檔案中的CheckPointRBA,當例項崩潰時,恢復將從CheckPointRBA所指向的日誌位置開始。這就是"增量檢查點"的行為和定義。CKPT程式也會記錄檢查點位置到資料檔案的頭部,但是隻是日誌切換時才寫。而不是每三秒。當檢查點發生時,DBWN不會一直不停的寫DB BUFFER中髒資料,它將寫到檢查點佇列的開始塊的Low RBA的值大於該檢查點的Checkpoint RBA的值時停止寫入,然後完成這次檢查點,CKPT程式將記錄該檢查點的有關資訊到控制檔案中去。


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

相關文章