天天看點

oracle技術分享之Oracle 資料塊

Oracle 資料塊(一)

1、資料塊的概念

資料塊(Oracle Data Blocks),本文簡稱為“塊”,是Oracle最小的存儲機關,Oracle資料存放在“塊”中。一個塊占用一定的磁盤空間。特别注意的是,這裡的“塊”是Oracle的“資料塊”,不是作業系統的“塊”。

Oracle每次請求資料的時候,都是以塊為機關。也就是說,Oracle每次請求的資料是塊的整數倍。如果Oracle請求的資料量不到一塊,Oracle也會讀取整個塊。是以說,“塊”是Oracle讀寫資料的最小機關或者最基本的機關。

塊的标準大小由初始化參數DB_BLOCK_SIZE指定。具有标準大小的塊稱為标準塊(Standard Block)。塊的大小和标準塊的大小不同的塊叫非标準塊(Nonstandard Block)。同一資料庫中,Oracle9i及以上版本支援同一資料庫中同時使用标準塊和非标準塊。Oracle允許指定5種非标準塊(Nonstandard Block)。

作業系統每次執行I/O的時候,是以作業系統的塊為機關;Oracle每次執行I/O的時候,都是以Oracle的塊為機關。

Oracle資料塊大小一般是作業系統塊的整數倍。

2、資料塊的格式(Data Block Format)

塊中存放表的資料和索引的資料,無論存放哪種類型的資料,塊的格式都是相同的,塊由塊頭(header/Common and Variable),表目錄(Table Directory),行目錄(Row Directory),空餘空間(Free Space)和行資料(Row Data)五部分組成。

如下圖所示。

塊頭(header/Common and Variable):存放塊的基本資訊,如:塊的實體位址,塊所屬的段的類型(是資料段還是索引段)。 表目錄(Table Directory):存放表的資訊,即:如果一些表的資料被存放在這個塊中,那麼,這些表的相關資訊将被存放在“表目錄”中。

行目錄(Row Directory):如果塊中有行資料存在,則,這些行的資訊将被記錄在行目錄中。這些資訊包括行的位址等。

行資料(Row Data):是真正存放表資料和索引資料的地方。這部分空間是已被資料行占用的空間。

空餘空間(Free Space):空餘空間是一個塊中未使用的區域,這片區域用于新行的插入和已經存在的行的更新。

頭部資訊區(Overhead):我們把塊頭(header/Common and Variable),表目錄(Table Directory),行目錄(Row Directory)這三部分合稱為頭部資訊區(Overhead)。頭部資訊區不存放資料,它存放的整個塊的資訊。頭部資訊區的大小是可變的。一般來說,頭部資訊區的大小介于84位元組(bytes)到107位元組(bytes)之間。

3、資料塊中自由空間的使用

當往資料庫中插入(INSERT)資料的時候,塊中的自由空間會減少;當對塊中已經存在的行進行修改(UPDATE)的時候(使記錄長度增加),塊中的自由空間也會減少。

DELETE語句和UPDATE語句會使塊中的自由空間增加。當使用DELETE語句删除塊中的記錄或者使用UPDATE語句把列的值更改成一個更小值的時候,Oracle會釋放出一部分自由空間。釋放出的自由空間并不一定是連續的。通常情況下,Oracle不會對塊中不連續的自由空間進行合并。因為合并資料塊中不連續的自由空間會影響資料庫的性能。隻有當使用者進行資料插入(INSERT)或者更新(UPDATE)操作,卻找不到連續的自由空間的時候,Oracle才會合并資料塊中不連續的自由空間。

對于塊中的自由空間,Oracle提供兩種管理方式:自動管理,手動管理

4、行連結和行遷移(Row Chaining and Migrating)

行連結(Row Chaining):如果我們往資料庫中插入(INSERT)一行資料,這行資料很大,以至于一個資料塊存不下一整行,Oracle就會把一行資料分作幾段存在幾個資料塊中,這個過程叫行連結(Row Chaining)。如下圖所示:

如果一行資料是普通行,這行資料能夠存放在一個資料塊中;如果一行資料是連結行,這行資料存放在多個資料塊中。

行遷移(Row Migrating):資料塊中存在一條記錄,使用者執行UPDATE更新這條記錄,這個UPDATE操作使這條記錄變長,這時候,Oracle在這個資料塊中進行查找,但是找不到能夠容納下這條記錄的空間,無奈之下,Oracle隻能把整行資料移到一個新的資料塊。原來的資料塊中保留一個“指針”,這個“指針”指向新的資料塊。被移動的這條記錄的ROWID保持不變。行遷移的原理如下圖所示:

無論是行連結還是行遷移,都會影響資料庫的性能。Oracle在讀取這樣的記錄的時候,Oracle會掃描多個資料塊,執行更多的I/O。

5、塊中自由空間的自動管理

Oracle使用位圖(bitmap)來管理和跟蹤資料塊,這種塊的空間管理方式叫“自動管理”。自動管理有下面的好處:

◆易于使用

◆更好地利用空間

◆可以對空間進行實時調整

6、塊中自由空間的手動管理

使用者可以通過PCTFREE, PCTUSED來調整塊中空間的使用,這種管理方式叫手動管理。相對于自動管理,手動管理方式比較麻煩,不容易掌握,容易造成塊中空間的浪費。

PCTFREE參數用于指定塊中必須保留的最小空閑空間百分例。之是以要預留這樣的空間,是因為UPDATE時,需要這些空間。如果UPDATE時,沒有空餘空間,Oracle就會配置設定一個新的塊,這會産生行遷移(Row Migrating)。

PCTUSED也是用于設定一個百分比,當塊中已使用的空間的比例小于這個百分比的時候,這個塊才被辨別為有效狀态。隻有有效的塊才被允許插入資料。

在向大家詳細介紹Oracle空閑資料塊之前,首先讓大家了解下復原段存儲的資料,然後全面介紹Oracle空閑資料塊,希望對大家有用。在這裡我們要說一下復原段存儲的資料,假如是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空閑資料塊,Oracle空閑資料塊可以通過Freelist或BITMAP來維護,它們位于一個段的頭部用來辨別目前段中哪些資料塊可以進行INSERT。在本地管理表空間中Oracle自動管理配置設定給段的區的大小,隻在本地管理的表空間中才能選用段自動管理,采用自動段空間管理的本地管理表空間中的段中的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最多為三級)。采用手動管理的本地管理表空間中的段和資料字典管理的表空間中的段中的Oracle空閑資料塊的管理都使用位于段頭部的空閑清單來管理,例如SYSTEM表空間是本地管理表空間,但是它是采用了手動段空間管理,是以也是用Freelist來管理段中的Oracle空閑資料塊的。空閑清單是一個邏輯上的連結清單,在段的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程序将記錄該檢查點的有關資訊到控制檔案中去。以上介紹Oracle空閑資料塊。

oracle視訊教程請關注:http://u.youku.com/user_video/id_UMzAzMjkxMjE2.html