深刻理解數據庫磁盤存儲(Disk Storage)

數據庫管理系統將數據存儲在磁盤、磁帶以及其餘的裸設備上,雖然這些設備的訪問速度相比內存慢不少,但其非易失性和大容量的特色使他們成爲數據存儲的不二之選。html

本文主要討論大型數據庫產品的磁盤存儲內部結構,這對於深刻理解數據庫各類數據結構具備相當重要的做用。數據庫

數據庫磁盤存儲的體系結構服務器

以上兩圖分別展現了存儲器分級結構以及磁盤內部物理結構,不是本文重點,不贅述。須要強調的是:一次完整的輸入輸出(IO)操做的時間=磁盤軸旋轉時間(旋轉延遲)+磁盤臂移動時間(尋道時間)+數據傳輸時間。三者所需時間的平均經驗值爲:0.004秒、0.008秒和0.0005秒。因此,一次完整的IO時間的經驗值是0.0125秒,即1/80秒。數據結構

對於大型數據庫而言,即使是這極短暫的0.0125秒,頻繁的IO操做會將這微不足道的時間累積得很是可觀,所以磁盤存儲的優化對於數據庫效率的提高是很是必要和重要的。不一樣的數據庫產品的磁盤存儲內部實現是不一樣的,本文只討論Oracle、DB2大型數據庫產品,兩者細節上雖有不一樣,但結構大致上是同樣的。併發

Oracle和DB2數據庫的存儲模型如圖:oracle

能夠看出,數據庫中的數據都存儲在表空間中。表空間便是管理將邏輯數據庫設計映射到操做系統物理存儲中的一個數據庫對象,用於指明數據的物理位置。關於表空間,之後再討論。jsp

Oracle數據庫磁盤存儲的邏輯結構爲:一個數據庫(Database)對應多個表空間(Tablespace),一個表空間對應多個段(Segment),一個段對應多個區(Extent),一個區對應多個數據塊(Data Block),真正的數據就保存在數據塊中。這裏有如下幾點須要說明:數據庫設計

1.Oracle中一個數據塊的大小默認是2KB(支持2KB,4KB,8KB,16KB,32KB),而DB2中則默認是4KB(支持4KB,8KB,16KB,32KB);性能

2.Oracle中有段(Segment)的概念,而DB2中沒有這一律念,表空間直接是各個容器(數據文件)中的區(Extent)組成,不過也仍是有一個很弱化的Extent組概念。下面提到的關於Segment的內容則所有是針對Oracle的;優化

3.Oracle中的數據塊稱爲Oracle Block,而DB2中則直接稱爲Data Page(數據頁)。

4.Oracle中的Extent稱爲區,而DB2中則稱爲擴展數據塊。爲方便閱讀,本文中統稱爲區。

                                 Oracle磁盤存儲邏輯結構

 

  

                                           DB2磁盤存儲邏輯結構

要注意:這裏的表空間,段,區,數據塊(頁)所有都是數據庫中的邏輯概念,並非物理存在的,那麼數據庫磁盤存儲的邏輯結構如何映射到操做系統磁盤存儲的物理結構中呢?

先來看看錶空間的物理映射。表空間在操做系統上是由容器(Container)承載的,對於系統管理表空間(SMS)【注意:Oracle不存在系統管理表空間,其表空間所有都是數據庫管理的】,其惟一的容器是文件目錄;而對於數據庫管理表空間,其容器則是文件或者裸設備(好比磁帶、磁盤櫃)。這裏咱們不討論系統管理表空間,只關注數據庫管理表空間下的數據庫磁盤存儲。因爲數據庫對於文件和裸設備這兩種容器操做上是同等對待的,因此以文件容器爲例進行討論。文件容器自己是一個由DMS表空間使用的預分配大小的文件,一個表空間能夠有多個文件容器,即有多個數據文件。也就是說:一個邏輯上的表空間映射爲多個物理上的數據文件。

再來討論數據塊(頁)的物理映射。咱們知道,物理結構上,操做系統中的文件是由多個操做系統的塊(Block)組成的(Linux,Unix系統的塊大小爲512B,而Windows系統的塊大小爲1KB),而上面說了,數據庫中的數據是以數據塊(頁)爲單位存放的,,那麼數據庫中的數據塊(頁)和操做系統的塊是什麼關係呢?事實上,若干個操做系統塊組成一個數據庫的數據塊(頁)。對應區(extent)和段(segment)的映射並無物理單位與之對應,而是在一個數據文件中會包含多個段,每一個段裏又包含多個區(每一個段中的區的個數不必定是同樣的;DB2中數據文件中直接以區爲單位,沒有段的概念),每一個區包含若干數據塊(每一個區中數據塊的數量也不必定同樣)。另外,和表空間同樣,段也是能夠跨文件的,即一個段能夠由不一樣文件中的區所組成。

數據庫磁盤存儲的邏輯/物理映射圖解以下(DB2中沒有Segment這一層):

關於這些邏輯單位的具體討論之後再說。如今只須要了解大致的體系結構。經過上面的介紹能夠看到,數據庫管理的表空間自成一體,具備平臺無關性,儼然是一個小型的獨立文件系統了。

數據庫磁盤存儲的內部實現

瞭解了磁盤存儲的體系結構,再來看一看數據庫系統中,數據具體是如何進行存儲的。

當建立一張表(Table)的時候,會爲其指定表空間,一旦表成功建立,數據庫系統就要爲表提供磁盤空間。

Oracle數據庫會自動爲一張表分配一個Segment(段),這個Segment稱爲Data Segment(數據段)【注:一張表只能被分配一個數據段。Oracle一共有四種類型的段,分別是Data Segment(數據段),Index Segment(索引段),Rollback Segment(回滾段)和Temp Segment(臨時段)】。當爲表分配的數據段所有寫滿的時候,數據庫管理系統會爲這個數據段增長新的區(Extent),也就是說,數據段空間分配完後並非須要多少空間就爲段增長多少空間,也不是直接在區中增長數據塊,而是一次性增長一個Extent(這樣作避免了頻繁的Segment擴容),Extent是空間分配的最小單位,並且Extent在表空間中的各個容器上是均衡分配的。另外,數據塊(頁)是最小的存儲單位,也即最小的I/O單位,全部數據都是按塊(頁)存儲,讀出的時候也是直接將整個數據塊(頁)讀入內存中的。至於DB2,其方案與Oracle基本相同,所不一樣的是沒有Segment分配的問題。

咱們以DB2爲例,看看數據存儲具體是怎樣的。【參考牛新莊:深刻解析DB2】

一個DMS表空間能夠有多個容器(文件或裸設備),DB2將Extent均衡的寫到各個容器上。即當須要請求一個Extent時,數據庫管理器這個Extent分配到下一個容器上。這種方案保證了各容器的均衡利用,提升了並行訪問效率。如左圖:

                                         表空間容器均衡寫

 

 

                      表空間容器,Extent,數據頁和表空間之間的關係

 

新建一個稱爲HUMANRES的DMS表空間,其Extent大小爲2個Page(即數據塊),每一個Page大小爲4KB。表空間有4個容器,每一個容器內有少許已分配的Extent:表空間中DEPARTMENT和EMPLOYEE表中都佔用了7個Page,按照上面介紹的分配規則,這兩個表中的數據都會寫到四個不一樣的容器中(7個Page須要分配4個Extent,每一個Extent依次分配到各個容器中),另外,一個Extent只能由一個表所寫,即使表數據不能徹底利用Extent中的空間,Extent中的空閒空間也只能空着,不能繼續寫入其餘表中的數據(這是由Extent是空間最小分配單位決定的)。如右圖。

數據塊(頁)存儲

下面進一步深刻,分析一下數據庫磁盤存儲最小單元數據塊(Data Block or Data Page)內的具體結構是怎樣的。對於Oracle和DB2,兩者的數據塊結構是不一樣的。如下分別討論。至於其餘的數據庫產品,不在討論之列。

Oracle數據庫的數據塊(Data Block)結構及相關特性

(參照:http://docs.oracle.com/cd/B28359_01/server.111/b28318/logical.htm

數據塊格式

Oracle 數據塊的格式不管是表、索引仍是cluster 數據,格式都是很相似的,如圖:

 

公共和變量塊頭( Common and Variable Header)

頭部包含了通用塊信息,例如塊的地址和段的類型 ( 例如表或者索引 )
表目錄(Table Directory)
這部分信息包含了在這個塊中該表或該索引的相關信息。
行目錄(Row Directory)
這部分包含了數據塊中的實際行的信息 ( 包括行數據區域中每行的地址 ) ,一旦數據塊頭部的這個行目錄的空間被分配了,那麼即便該行刪除了,這段空間仍然不能回收。
所以一個當前爲空的數據塊,此區域包含數據塊中存儲的數據行的信息(每一個數據行片段( row piece ) 在行數據區( row data area )中的地址)。 [ 一個數據塊中可能保存一個完整的數據行,也可能只保存數據行的一部分 ,因此文中使用 row piece] 。只有在數據塊中插入( insert )新數據時,行目錄區空間纔會被從新利用。
頭部信息區(Overhead )
塊頭( header/Common and Variable ),表目錄( Table Directory ),行目錄( Row Directory )這三部分合稱爲頭部信息區( Overhead )。頭部信息區不存放數據,它存放的整個塊的信息。頭部信息區的大小是可變的。通常來講,頭部信息區的大小介於 84 字節( bytes )到 107 字節( bytes )之間。
可用空間(Free Space)
可用空間是一個塊中未使用的區域,這片區域用於新行的插入和已經存在的行的更新。可用空間也包含事務條目,當每一次 insert 、 update 、 delete 、 select ..for update 語句訪問塊中一行或多行數據,將會請求一條事務條目,事務條目的請求空間與操做系統相關,在多數操做系統中大約所需 23 個字節。
行數據(Row Data)
這部數據塊包含了表或索引的數據,行也可能跨數據塊,這也就是行遷移現象。
 
可用空間管理(Free Space Management)
可用空間多是自動或人工管理。
可用空間是由 Oracle 內部的段自動管理的,段內的可用 / 已用空間用位圖來跟蹤。自動段空間管理提供瞭如下好處:
l  使用便捷
l  更好的空間利用率,特別是那些行大小變化很大的對象
l  併發訪問的動態調整
l  性能 / 空間的平衡
數據塊可用空間的利用和壓縮
Delete 和 update( 把原值變小 ) 可增長數據塊的可用空間。在如下狀況下 insert 語句纔能有效地利用已釋放的空間。
假如 insert 語句在同一個事務中,而 insert 前面的語句恰好釋放了相應的空間,這時候 insert 語句能夠利用該空間
假如 insert 語句與釋放空間的語句不在同一個事務中,那麼只有當其餘事務提交後而且恰好須要空間的時候, insert 語句才能利用該空間。
釋放的空間也可能不是連續的,只有當 如下兩個條件都知足的時候, Oracle 纔會合併和壓縮數據塊的可用空間。
1 一個 insert 或 update 語句試圖使用足夠空間建立新行的時候;
2 自由空間是分散的以致於不能插入毗鄰空間的時候;
這就是所謂的「塊重組(Block Reorganization)」。事實上,Oracle和DB2在對待碎片空間上的策略是一致的,即:行數據被刪除後,該空間空置,當塊空間不足時進行重組。而其餘數據庫的策略是行數據刪除後,其餘行數據順移以保證可用空間是連續的。顯然,這種作法影響數據庫效率。
 
行連接和行遷移(Row Chaining and Migrating )
行連接( Row Chaining ):若是咱們往數據庫中插入( INSERT )一行數據,這行數據很大,以致於一個數據塊存不下一整行, Oracle 就會把一行數據分做幾段存在幾個數據塊中,這個過程叫行連接( Row Chaining )。
若是一行數據是普通行,這行數據可以存放在一個數據塊中;若是一行數據是連接行,這行數據存放在多個數據塊中。
行連接又稱爲行跨頁,Oracle容許行跨頁,但DB2是不容許的。

行遷移 (Row Migrating) :數據塊中存在一條記錄,用戶執行 UPDATE 更新這條記錄,這個 UPDATE 操做使這條記錄變長,這時候, Oracle 在這個數據塊中進行查找,可是找不到可以容納下這條記錄的空間,無奈之下, Oracle 只能把整行數據移到一個新的數據塊。原來的數據塊中保留一個「指針」,這個「 指針」指向新的數據塊。被移動的這條記錄的 ROWID 保持不變。
 
 
PCTFREE和PCTUSED
PCTFREE 參數用於指定塊中必須保留的最小空閒空間百分例。之因此要預留這樣的空間,是由於 UPDATE 時,須要這些空間。若是 UPDATE 時,沒有空餘空間, Oracle 就會分配一個新的塊,這會產生行遷移( Row Migrating ),進行空間預留可以必定程度上保證數據庫訪問效率。
PCTUSED 也是用於設置一個百分比,當塊中已使用的空間的比例小於這個百分比的時候,這個塊才被標識爲有效狀態。只有有效的塊才被容許插入數據。
PCTFREE和PCTUSED做用示意圖以下:

DB2數據庫的數據頁(Data Page)結構及相關特性

 

 

(參照:http://pic.dhe.ibm.com/infocenter/db2luw/v9r7/index.jsp?topic=%2Fcom.ibm.db2.luw.admin.perf.doc%2Fdoc%2Fc0007337.html

數據頁格式

 

在標準表中,數據在邏輯上按數據頁的列表進行組織。這些數據頁根據表空間的Extent大小在邏輯上分組到一塊兒。這個Extent組相似於Oracle中的Segment,但Extent組沒有Segment那樣的強制概念。

每一個數據頁都具備相同的格式。每一頁的最前面都是頁頭,後面跟着槽(Slot)目錄,而後是可用空間和記錄。

頁頭(Header)

用於存放BPS HEADER和一些頁的信息字段,其中BPS HEADER佔48字節,整個頁頭大概佔91個字節。

槽目錄(Slot Directory)

槽目錄相似Oracle的數據塊中的行目錄,槽目錄中的每一個條目都與該頁中的一個記錄相對應。槽目錄中的條目表明記錄開始位置在數據頁中的字節偏移。值爲 -1 的條目與已刪除的記錄相對應。

可用空間(Free Space)

DB2可用空間嚴格來講包括一般意義上的常規可用空間和嵌入的可用空間。其中常規可用空間可用直接存儲數據,而嵌入的可用空間一般是記錄被刪除後產生的碎片空間,不能直接使用,只有當頁重組後合併到常規可用空間後才能被使用,這一點和Oracle相似。

記錄(Record)

已經存儲了數據的空間,相似於Oracle中的行數據。即表中的行存放於頁面中成爲記錄。根據數據頁大小以及記錄大小的不一樣,每一個數據頁中包含的記錄數(即行數據數)也會有所變化。大多數頁僅包含用戶記錄(即普通的數據庫數據)。可是,少數頁包含由數據服務器用於管理表的特殊內部記錄。例如,在標準表中,每 500 個數據頁就有一個可用空間控制記錄(FSCR)。這些記錄用於映射後續每 500 個數據頁(直到下一個 FSCR 爲止)中可供新記錄使用的可用空間。另外,在DB2 V9以前,每一個數據頁最多能夠存放255條記錄,而DB2 V9以後,每一個數據頁理論上能夠存放65000條記錄(與RID有關,暫不討論),但實際上受限於數據頁大小,每一個數據頁大概能存放2300多條記錄。

行連接和行遷移

DB2是不容許行(記錄)跨頁的,即不容許行連接。可是容許行遷移(DB2中又稱爲行溢出),

當表中存在變長數據類型時,容易發生行溢出現象,行溢出有時也叫行遷移,它表示當咱們更新變長數據類型的字段時,因爲更新的數據長度比原數據長,以致於當前的數據頁沒法存放整行數據時,就須要把這行數據存放到一個新的數據頁,並在原來的數據頁內存放該行新位置的指針以指向新行位置,被移動的數據的RID(RID之後討論)保持不變。顯然,若是大規模出現行遷移的現象,那麼必然會對數據庫訪問的效率產生嚴重影響(I/O大幅增長),若是表中發現大量行遷移現象,建議進行重組(REORG)操做,從新規劃數據存儲位置消除行溢出。

 

對應DB2數據頁還須要強調的一點是:DB2的數據頁和Oracle數據塊同樣,也有PCTFREE和PCTUSED的概念,其含義與做用也大體相同,不贅述。

 

另外能夠看到,Oracle的數據塊結構和DB2的數據頁結構是很是類似的。還有一點,兩者的行數據都是從高位開始向低位寫,而行目錄則是由低位向高位寫,爲何要這樣呢?由於數據的插入是一個兩頭寫的過程,既要將數據寫入到可用空間中成爲行數據或記錄,又要更新頭部後面的行目錄或槽目錄,若是同側寫不利於空間的擴展。下圖是一個直觀圖:

 

數據行結構

如今對數據塊(頁)的具體結構已經有了一個大概的瞭解,那麼表中的一行數據是怎樣以行數據(記錄)的形式保存在數據塊(頁)中的呢?這個問題看似簡單,實際上,一個數據行(記錄,即上圖中的Row)的結構是很是複雜的,這裏以DB2中數據行的結構爲例。如圖:

各參數解釋以下:

能夠看到,當元組(即表中的行)中存在變長列的時候,無論該列位於什麼位置,在數據行(記錄)中都被挪到最後面存儲,而定長列則順序存儲。

【注:表的屬性列在定義的時候指定了數據類型,有的數據類型是變長的,好比varchar,其大小隨實際值的變化而變化,有的列數據類型的定長的,好比int爲32位,物理該列上的實際值是多少,都佔用4個字節。一旦列中出現變長數據類型的列,則該元組爲變長元組。】

下圖是狀態位A的每一位的含義(1個字節=8位),狀態位B是未使用的。

下面看看一個定長的元組(行)在數據行(記錄)中具體是如何存放的:

有些複雜,將此圖與前面貼的結構圖對照着看。【注意:全部數據在數據頁的數據行(記錄)中都是以十六進制存放的,且爲逆序存放】

下面是變長的元組(行)在數據行(記錄)中具體存放方式,與定長元組的存放方式大同小異:

對於含大對象數據類型的元組,其大對象數據並不與數據行存放在一塊兒,而是與數據行分開放置於數據庫的不一樣頁中,在該元組(行)的數據行中存放一個指向該大對象的指針。如圖:

 

以上就是數據庫系統磁盤存儲內部結構的大體內容了

 

 

https://blog.csdn.net/u011537073/article/details/49157903 ,若有侵權,請聯繫 linjie.rd@gmail.com 刪除

相關文章
相關標籤/搜索