oracle中數據文件的描述

數據文件和重做日誌文件是數據庫中最重要的文件。

您的數據最終就是要存儲在數據文件中。每個數據庫都至少有一個相關的數據文件,通常還不止一個。最簡單的“測試”數據庫只有一個數據文件。其中用最簡單的CREATE DATABASE命令根據默認設置創建了一個數據庫,這個數據庫中有兩個數據文件,其中一個對應SYSTEM表空間(真正的Oracle數據字典),另一個對應SYSAUX表空間(在10g及以上版本中,非字典對象都存儲在這個表空間中)。不過,所有實際的數據庫都至少有3個數據文件;一個存儲SYSTEM數據,一個存儲SYSAUX數據,還有一個存儲USER數據。

簡要回顧文件系統類型之後,我們將討論如何組織這些文件,以及文件中如何組織數據。要了解這些內容,需要知道什麼是表空間(tablespace)、什麼是段(segment)、什麼是區段(extent),以及什麼是塊(block)。這些都是Oracle在數據庫中存儲對象所用的分配單位,稍後將詳細介紹。

簡要回顧文件系統機制

在Oracle中,可以用4種文件系統機制存儲您的數據。這裏強調了“您的數據”,是指您的數據字典、redo記錄、undo記錄、表、索引、LOB等,也就是您自己每天關心的數據。簡單地講,這包括:

a)“Cooked”操作系統(OS)文件系統:這些文件就像字處理文檔一樣放在文件系統中。在Windows 資源管理器中可以看到這些文件,在UNIX上,可以通過ls命令看到這些文件。可以使用簡單的OS工具(如Windows上的xcopy或UNIX上的cp)來移動文件。從歷史上看,Cooked OS文件一直是Oracle中存儲數據的“最流行”的方法,不過我個人認爲,隨着ASM(稍後再詳細說明)的引入,這種情況會有所改觀。Cooked文件系統(“加工”文件系統或“熟”文件系統)通常也會緩存,這說明在您讀寫磁盤時,OS會爲您緩存信息。

b)原始分區(raw partitions,也稱裸分區):這不是文件,而是原始磁盤。不能用ls來查看;不能在Windows資源管理器中查看其內容。它們就是磁盤上的一些大扇區,上面沒有任何文件系統。對Oracle來說,整個原始分區就是一個大文件。這與cooked文件系統不同,cooked文件系統上可能有幾十個甚至數百個數據庫數據文件。目前,只有極少數Oracle安裝使用原始分區,因爲原始分區的管理開銷很大。原始分區不是緩衝設備,所完成的所有I/O都是直接I/O,對數據沒有任何OS緩衝(不過,對於數據庫來說,這通常是一個優點)。

c)自動存儲管理(Automatic Storage Management,ASM):這是 Oracle 10g Release 1 的一個新特性(標準版和企業版都提供了這個特性)。ASM是專門爲數據庫設計的文件系統。可以簡單地把它看作一個數據庫文件系統。在這個文件系統上,不是把購物清單存儲在文本文件中;這裏只能存儲與數據庫相關的信息:您的表、索引、備份、控制文件、參數文件、重做日誌、歸檔文件等。不過,即使是ASM,也同樣存在着相應的數據文件;從概念上講,數據庫仍存儲在文件中,不過現在的文件系統是ASM。ASM設計成可以在單機環境或者集羣環境中工作。

d)集羣文件系統:這個文件系統專用於RAC(集羣)環境,看上去有些像由集羣環境中多個節點(計算機)共享的cooked文件系統。傳統的cooked文件系統只能由集羣環境中的一臺計算機使用。所以,儘管可以在集羣中的多個節點之間使用NFS裝載或Samba共享一個cooked文件系統(Samba與NFS類似,可以在Windows/UNIX環境之間共享磁盤),但這會導致一損俱損。如果安裝有文件系統並提供共享的節點失敗,這個文件系統都將不可用。Oracle集羣文件系統(Oracle Cluster File System,OCFS)是Oracle在這個領域推出的一個新的文件系統,目前只能在Windows和Linux上使用。其他第三方開發商也提供了一些經認證的集羣文件系統,也可以用於Oracle。集羣文件系統讓cooked文件系統的優點延伸到了集羣環境中。

有意思的是,數據庫可能包含來自上述所有文件系統中的文件,您不必只選其中的一個。在您的數據庫中,可能部分數據存儲在一個傳統的cooked文件系統中,有些在原始分區上,有一些在ASM中,還有一些在集羣文件系統中。這樣就能很容易地切換技術,或者只是涉及一個新的文件系統,而不必把整個數據庫都搬到這個文件系統中。現在,因爲完整地討論文件系統及其詳細的屬性超出了本書的範圍,所以我們還是回過頭來深入探討Oracle文件類型。不論文件是存儲在cooked文件系統、原始分區、ASM中,還是存儲在集羣文件系統中,以下概念都適用。

  Oracle數據庫中的存儲層次體系

數據庫由一個或多個表空間構成。表空間(tablespace)是Oracle 中的一個邏輯存儲容器,位於存儲層次體系的頂層,包括一個或多個數據文件。這些文件可能是文件系統中的cooked文件、原始分區、ASM管理的數據庫文件,或者是集羣文件系統上的文件。表空間包含段,請看下面的介紹。
1. 段
現在開始分析存儲層次體系,首先討論段,這是表空間中主要的組織結構。段(segment)就是佔用存儲空間的數據庫對象,如表、索引、回滾段等。創建表時,會創建一個表段。創建分區表時,則每個分區會創建一個段。創建索引時,就會創建一個索引段,依此類推。佔用存儲空間的每一個對象最後都會存儲在一個段中,此外還有回滾段(rollback segment)、臨時段(temporary segment)、聚簇段(cluster segment)、索引段(index segment)等。
注意    上面有這樣一句話:“佔用存儲空間的每一個對象最後都會存儲在一個段中”,這可能會把你搞糊塗。你會發現許多CREATE語句能創建多段的對象。之所以會產生困惑,原因是一條CREATE語句最後創建的對象可能包含0個、1個或多個段!例如,CREATE TABLE T ( x int primary key, y clob)就會創建4個段:一個是TABLE T的段,還有一個段對應索引(這個索引是爲支持主鍵而創建的),另外還有兩個CLOB段(一個CLOB段是LOB索引,另一個段是LOB數據本身)。與之不同,CREATE TABLE T ( x int, y date ) cluster MY_CLUSTER則不會創建任何段。第10章還會更深入地討論這個概念。
2. 區段
段本身又由一個或多個區段組成。區段(extent)是文件中一個邏輯上連續分配的空間(一般來講,文件本身在磁盤上並不是連續的;否則,根本就不需要消除磁盤碎片的工具了!)。另外,利用諸如獨立磁盤冗餘陣列(Redundant Array of Independent Disks,RAID)之類的磁盤技術,你可能會發現,一個文件不僅在一個磁盤上不連續,還有可能跨多個物理磁盤。每個段都至少有一個區段,有些對象可能還需要至少兩個區段(回滾段就至少需要兩個區段)。如果一個對象超出了其初始區段,就會請求再爲它分配另一個區段。第二個區段不一定就在磁盤上第一個區段旁邊,甚至有可能不在第一個區段所在的文件中分配。第二個區段可能與第一個區段相距甚遠,但是區段內的空間總是文件中的一個邏輯連續空間。區段的大小可能不同,可以是一個Oracle數據塊,也可以大到2 GB。
3. 塊
區段又進一步由塊組成。塊(block)是Oracle中最小的空間分配單位
。數據行、索引條目或臨時排序結果就存儲在塊中。通常Oracle從磁盤讀寫的就是塊。Oracle中塊的常見大小有4種:2 KB、4 KB、8 KB或16 KB(儘管在某些情況下32 KB也是允許的;但是操作系統可能對最大大小有限制)。
注意    有一點可能很多人都不知道:數據庫的默認塊大小不必是2的冪。2的冪只是一個常用的慣例。實際上,你完全可以創建塊大小爲5 KB、7 KB或n KB的數據庫,這裏n介於2~32 KB之間。不過,我還是建議你在實際中不要考慮這樣做,塊大小還是用2 KB、4 KB、8 KB或16 KB比較好。

一個段由一個或多個區段組成,區段則由連續分配的一些塊組成。從Oracle9i Release 1起,數據庫中最多可以有6種不同的塊大小(block size)。

注意    之所以引入這個特性,即一個數據庫中允許有多種塊大小,目的是爲了可以在更多的情況下使用可傳輸的表空間。如果能傳輸表空間,DBA就能從一個數據庫移動或複製格式化的數據文件,把它放在另一個數據庫中,例如,可以從一個聯機事務處理(Online Transaction Processing,OLTP)數據庫中把所有表和索引複製到一個數據倉庫(Data Warehouse,DW)中。不過,在許多情況下,OLTP數據庫使用的塊大小可能很小,如2 KB或4 KB,而DW使用的塊大小可能很大(8 KB或16 KB)。如果一個數據庫中不支持多種塊大小,就無法傳輸這些信息。有多種塊大小的表空間主要用於傳輸表空間,一般沒有其他用途。

數據庫還有一個默認的塊大小,即執行CREATE DATABASE命令時初始化文件中指定的大小。SYSTEM表空間總是使用這個默認塊大小,不過你完全可以按非默認塊大小(2 KB、4 KB、8 KB或16 KB)創建其他表空間,如果操作系統允許,還可以使用32 KB的塊大小。當且僅當創建數據庫時指定了一個非標準的塊大小(不是2的冪)時,纔會有6種不同的塊大小。因此,在實際中,數據庫最多有5種不同的塊大小:默認大小和另外4種非默認的塊大小。

在所有給定的表空間內部,塊大小都是一致的,這說明,一個表空間中的所有塊大小都相同。對於一個多段對象,如一個包含LOB列的表,可能每個段在不同的表空間中,而這些表空間分別有不同的塊大小,但是任何給定段(包含在表空間中)都由相同大小的塊組成。無論大小如何,所有塊格式都一樣,
塊首部(block header)包含塊類型的有關信息(表塊、索引塊等)、塊上發生的活動事務和過去事務的相關信息(僅事務管理的塊有此信息,例如臨時排序塊就沒有事務信息),以及塊在磁盤上的地址(位置)。塊中接下來兩部分是表目錄和行目錄,最常見的數據庫塊中(即堆組織表的數據塊)都有這兩部分。以後將更詳細地介紹數據庫表類型,不過,現在知道大多數表都是這種類型就足夠了。如果有表目錄(table directory),則其中會包含把行存儲在這個塊上的表的有關信息(可能一個塊上存儲了多個表的數據)。行目錄(row directory)包含塊中行的描述信息。這是一個指針數組,指向塊中數據部分中的行。塊中的這3部分統稱爲塊開銷(block overhead),這部分空間並不用於存放數據,而是由Oracle用來管理塊本身。塊中餘下的兩部分就很清楚了:塊上可能有一個空閒空間(free space),通常還會有一個目前已經存放數據的已用空間(used space)。

從以上介紹可以知道,段由區段組成,區段由塊組成,對段有了大致的瞭解後,下面再來更深入地分析表空間,然後說明文件在這個存儲層次體系中的位置。

4. 表空間

前面已經提到,表空間是一個容器,其中包含有段。每個段都只屬於一個表空間。一個表空間中可能有多個段。一個給定段的所有區段都在與段相關聯的表空間中。段絕對不會跨越表空間邊界。表空間本身可以有一個或多個相關的數據文件。表空間中給定段的一個區段完全包含在一個數據文件中。不過,段可以有來自多個不同數據文件的區段
表空間是Oracle中的邏輯存儲容器。作爲開發人員,我們會在表空間中創建段,而絕對不會深入到原始的“文件級”。我們可不希望在一個特定的文件中分配區段(當然這也是可以的,但我們一般都不會這麼做)。相反,我們會在表空間中創建對象,餘下的工作都由Oracle負責。如果將來某個時刻DBA決定在磁盤上移動數據文件,從而使I/O分佈得更均勻,這對我們來說沒有任何關係,它根本不會影響我們的處理。

5. 存儲層次體系小結

總結一下,Oracle中的存儲層次體系如下:

(1) 數據庫由一個或多個表空間組成。

(2) 表空間由一個或多個數據文件組成。這些文件可以是文件系統中的cooked文件、原始分區、ASM管理的數據庫文件,或集羣文件系統上的文件。表空間包含段。

(3) 段(TABLE、INDEX等)由一個或多個區段組成。段在表空間中,但是可以包含這個表空間中多個數據文件中的數據。

(4) 區段是磁盤上一組邏輯連續的塊。區段只在一個表空間中,而且總是在該表空間內的一個文件中。

(5) 塊是數據庫中最小的分配單位,也是數據庫使用的最小I/O單位。

字典管理和本地管理的表空間

在繼續討論之前,我們再來看看關於表空間的一個問題:在表空間中如何管理區段。在Oracle 8.1.5之前,表空間中管理區段的分配只有一種方法:字典管理的表空間(dictionary-managed tablespace)。也就是說,表空間中的空間在數據字典表中管理,這與管理賬戶數據(利用DEBIT和CREDIT表)的方法是一樣的。借方有已經分配給對象的所有區段。貸方是所有可用的自由區段。如果一個對象需要另一個區段,就會向系統“申請”。然後Oracle訪問其數據字典表,運行一些查詢,查找到空間(也許找不到),然後更新一個表中的一行(或者從表中將這一行刪除),再向另一個表插入一行。Oracle管理空間與你編寫應用可謂異曲同工:同樣是要修改數據以及移動數據。

爲了得到額外的空間而在後臺代表你執行的SQL稱爲遞歸SQL(recursive SQL)。你的SQL INSERT語句會導致執行其他遞歸SQL來得到更多空間。如果頻繁地執行這種遞歸SQL,開銷可能相當大。對數據字典的這種更新必須是串行的;它們不能同時進行,所以要儘量避免。

在Oracle的早期版本中,可以看到,這種空間管理問題(遞歸SQL開銷)在“臨時表空間”中最常見(這還不是“真正的”臨時表空間,真正的臨時表空間是通過CREATE TEMPORARY TABLESPACE命令創建的)。空間會頻繁地分配(從字典表刪除,而插入到另一個表)和撤銷(把剛移動的行再移回原來的位置)。這些操作必須串行執行,這就大大削弱了併發性,而增加了等待時間。在7.3版本中,Oracle引入了一個真正的臨時表空間(true temporary tablespace)概念,這是一個新的表空間類型,專門用於存儲臨時數據,從而幫助緩解這個問題。在引入這個特殊的表空間類型之前,臨時數據與永久數據在同樣的表空間中管理,處理方式也與永久數據一樣。

而臨時表空間則不同,你不能在其中創建自己的永久對象。實際上根本的區別只有這一條;空間還是在數據字典表中管理。不過,一旦在臨時表空間中分配了一個區段,系統就會一直持有(也就是說,不會把空間交回)。下一次有人出於某種目的在臨時表空間中請求空間時,Oracle會在其內部的已分配區段列表中查找已經分配的區段。如果找到,就會直接重用,否則還是用老辦法來分配一個區段。採用這種方式,一旦數據庫啓動,並運行一段時間,臨時段看上去就好像滿了,但是實際上只是“已分配”。裏面都是空閒區段,它們的管理完全不同。當有人需要臨時空間時,Oracle會在內存中的數據結構裏查找空間,而不是執行代價昂貴的遞歸SQL。

在Oracle 8.1.5及以後版本中,Oracle在減少這種空間管理開銷方面又前進了一步。它引入了一個本地管理表空間(locally-managed tablespace )概念,而不是字典管理表空間。與Oracle 7.3中對臨時表空間的管理一樣,本地空間管理採用了同樣的辦法來管理所有表空間:這樣就無需使用數據字典來管理表空間中的空間。對於本地管理表空間,會使用每個數據文件中存儲的一個位圖來管理區段。現在要得到一個區段,系統所做的只是在位圖中將某一位設置爲1。要釋放空間,系統再把這一位設置爲0。與使用字典管理的表空間相比,這樣分配和釋放空間就相當快。爲了處理跨所有表空間的空間請求,我們不再需要在數據庫級串行完成這些耗時的操作,相反,只需在表空間級串行執行一個速度相當快的操作。本地管理的表空間還有另外一些很好的特點,如可以保證區段的大小統一,不過這一點DBA更關心。

再往後,則只應使用本地管理的表空間作爲存儲管理方法。實際上,在Oracle9i及以上版本中,如果使用數據庫配置助手(database configuration assistant,DBCA)創建一個數據庫,它就會創建一個SYSTEM作爲本地管理的表空間,如果SYSTEM是本地管理的,那麼該數據庫中所有其他表空間也會是本地管理的,而且遺留的字典管理方法將無法工作。如果數據庫中的SYSTEM是本地管理的表空間,並不是說這樣的數據庫中不支持字典管理的表空間,而是說其中根本無法創建字典管理的表空間:

這是一個正面的副作用,因爲這樣可以杜絕你使用遺留的存儲機制,要知道它的效率相對較低,而且很可能導致碎片。本地管理的表空間除了在空間分配和撤銷方面效率更高以外,還可以避免出現表空間碎片,這正是以本地管理表空間的方式分配和撤銷空間的一個副作用

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章