5.oracle的dump理解五 數據塊理論
前兩篇描述了我們在操作層面看到的一些東西,但是沒有理論指導,看到越多我們只會越迷糊。所以,蛤蟆從官方文檔上摘取一些老少皆宜的內容來補腦。
塊是數據塊IO的最小單位。
1 數據塊和操作系統塊
從物理層面,數據庫的塊存儲時候是由操作系統塊組成。操作系統塊是操作系統可以讀寫的最小數據單位。ORACLE塊是一個邏輯存儲結構結構,大小和結構對操作系統是透明的。
如下圖1:
數據塊大小和操作系統塊大小是可以不一樣的,數據塊請求多個數據塊,不是多個操作系統塊。
當數據庫請求一個數據塊,操作系統轉換這個請求操作到存儲上。數據塊的邏輯分離有一下兩點:
n 應用層面不需要確定磁盤上數據的物理地址
n 數據塊可以條帶或鏡像到多個物理磁盤
1.1 數據塊大小
每個數據塊都有一個數據塊塊大小。有初始化參數DB_BLOCK_SIZE初始化參數在創建庫的時候設置。如果沒有設置就使用操作系統默認的塊大小來制定。標准的數據塊大小是4KB或8KB。如果和操作系統塊大小不一樣,必須是操作系統的倍數。
1.2 表空間塊大小
在創建獨立的表空間的時候使用不同於DB_BLOCK_SIZE大小的塊大小。
2 塊格式
每個數據塊都有一個格式或內部結構來使能數據塊來跟蹤數據和空閑空間。存放表,索引還是表族數據都是相似的。
如下圖2:
2.1 數據塊Overhead
數據塊的Overhead蛤蟆不知道翻譯成什么,就不翻譯了。
數據塊使用Overhead來管理塊本身。不能用於存儲用戶數據。這就說明雖然每個塊大小假設是8KB,但是實際可用的其實並沒有這么多的。
Overhead包含如下幾個部分:
2.1.1 塊頭
塊頭包含塊的通用信息,例如塊地址,段類型。對於交易管理的塊,塊頭包含了活動和歷史的交易信息。
每個更新塊都需要一個交易入口(transaction entry)。ORACLE數據塊初始化保留了這些空間。每個交易入口需要的空間取決於操作系統平台。一般是23個字節左右。
2.1.2 表目錄
對於堆表,這個目錄包含存在這個塊的表的元數據塊。對於簇表,多個表會存儲行在同一個塊中。
2.1.3 行目錄
對於堆表,該目錄描述行在塊中的位置。數據塊會把行放到塊底部的任何位置。行地址記錄在該目錄向量中。
一個rowid指向特定文件,塊和行位置。例如ROWID:AAAPecAAFAAAABSAAA最后3個AAA表示行號.行號是行目錄中索引。行目錄包含指向塊中數據的指針。如果從塊中移動一行,數據塊會修改行目錄中的指針,ROWID保持不變。
數據庫在行目錄分配空間后,刪除行后數據塊不會回收這個空間。因此,一個當前是空的塊(曾有50行的塊)可能分配了100個字節在行目錄。數據塊在插入行的時候會重新使用這空間。
OverHead中的有些部分是固定的,但是整體是變化的。平均在84~107字節。
2.2 行格式
一個塊中除了Overhead,剩下的都是行了。就是真正放數據的地方了。
行數據保持真正的數據,例如表行或索引鍵。每個數據塊有內部格式,每個行也有行格式使得數據塊來跟蹤數據。
Oracle數據塊通過變長記錄來存儲行。一個行包含一個或多個段。每個段叫做行片(rowpiece),每個行片有一個行頭和列數據。
如下圖3:
2.2.1 行頭
ORACLE數據使用行頭來管理行片在塊中的存儲。行頭包含以下信息:
l 行片中的列數量
l 在其他塊中的行片(如果完整的行在一個數據塊中,那么行作為一個行片,如果不能在一個塊中存儲,那么會被存儲在多個行片中)
l 簇表的簇鍵
一個塊中完整包含一個行至少需要3個字節的行頭。
2.2.2 列數據
行頭之后,列數據段保存實際的數據。一般,存儲列的順序和CREATE TABLE語句一致,但是順序不能保證。例如,LONG類型一般最后創建。
在行片中的每個列,數據庫分開存儲列長度和數據。空間取決於數據類型。如果是可變的,那么會需要空間來增長或變小。
在塊頭中的行目錄上的有個槽指向行。
2.2.3 ROWID格式化
ORACLE使用ROWID來唯一指定一行。ROWID是數據塊用來訪問行的結構。一個ROWID物理上不存在數據塊上,但是和數據所在的文件和塊相關。
ROWIW格式如下圖4:
分為4個段,第一個是數據對象號,表簇有相同的數據對象號。
第二個是相對文件號,第三個是塊號,第四個是行號。
ROWID指向一個行片后,ROWID在一些情況下可以改變。例如,發生行移動,分區鍵更新,閃回表操作等。
內部數據塊執行行移動是物理上先刪除然后在插入。但是行移動是被當做UPDATE,可能會觸發觸發器。
3 塊壓縮
數據塊可以使用表壓縮來消除數據塊中重復值。
數據塊的格式不管是否壓縮都是一樣的。區別在於,塊開始存儲時候存儲了一個符號表。使用符號表中的短符號來代替重復的值。
例如:
2190,13770,25-NOV-00,S,9999,23,161
2225,15720,28-NOV-00,S,9999,25,1450
34005,120760,29-NOV-00,P,9999,44,2376
9425,4750,29-NOV-00,I,9999,11,979
1675,46750,29-NOV-00,S,9999,19,1121
壓縮后如下:
2190,13770,25-NOV-00,S,%,23,161
2225,15720,28-NOV-00,S,%,25,1450
34005,120760,*,P,%,44,2376
9425,4750,*,I,%,11,979
1675,46750,*,S,%,19,1121
使用*來替換29-NOV-00
使用%來替換9999
符號表如下圖5:
4 數據塊中的空間管理
數據塊填充數據塊從底部開始,空閑空間位於行數據和塊頭之間。在UPDATE時候自由空間會減少。數據庫管理空閑空間來優化性能避免浪費空間。
4.1 空閑空間百分比
PCTFREE參數指定如何管理自由空間。PCTFREE是重要的避免行遷移和空間浪費。
如果更新少,可以如下設置:
CREATETABLE test_table (n NUMBER) PCTFREE 20;
如下圖6所示
PCTFREE設置為20,需要至少有20%的塊是空閑的。預留20%是用於現存行更新的使用。
4.2 數據塊中優化空閑空間
空間空間的比例不能少於PCTFREE,但是可以超過20%的。
以下命令可以增加塊中的空閑空間:
l DELETE
l UPDATE(將存在的值改成更小的值,或者讓行發生遷移)
l INSERT(插入喚醒塊壓縮,導致更多空閑空間)
insert釋放空間注意下面2點:
1、 本次交易的插入語句釋放后,還是本次交易使用該空間;
2、 如果是其他交易釋放的空間,需要其他交易COMMIT后才能使用
4.3 合並碎片空間
釋放的空間可能不是連續的,如下圖7所示
當一下條件發生時候,ORACLE自動合並空閑空間
l INSERT或UPDATE命令企圖使用塊中空間來包含新行
l 空閑空間太分散不能插入到塊中連續的空間中
合並后,空閑空間就連續了。
合並只有在條件滿足才執行,因為會該動作是會影響性能的。
4.4 行連接和行遷移
數據塊必須管理太大的行存儲在單個塊中。
l 當第一次插入時候,行太大。ORACLE存儲該行使用段保留的多個塊連接。行連接在大行時候經常發生。例如包含LONG或者LONGRAW。不可避免的。
l 當行被更新的長度增加,剩下的空間不能保持更新的行。發生行遷移,將整行移動新的數據塊,原來行片中保存一個指針指向新的位置。ROWID並沒有發生改變。
l 一行超過255列,一個行片中只能保持255個列。如果超過的話,需要鏈接多個塊了。
當行遷移或鏈接后,IO就會增加。
5 索引塊
索引塊是特殊類型的塊,和表塊有些不同。數據塊使用索引塊來管理索引的邏輯存儲空間。
索引塊類型有如下:
根塊:索引入口
分支塊:搜索索引鍵時候的導航塊
葉塊:包含索引鍵值ROWID,指向表中的相關行。
5.1 索引入口存儲
索引入口存儲方式和表行在數據塊中存儲一樣。索引在塊中的不是按二進制順序存儲,而是用堆的方式。
數據塊管理行目錄的方式和數據塊有些不同。行目錄中的是根據鍵值排序的。提高了索引掃描的效率。
5.2 索引塊槽位復用
索引塊比堆表的表塊有更多行。在一個單獨索引塊中存儲很多行,可以讓數據塊管理更簡單因為可以避免頻繁的分裂塊。
數據塊可以復用索引塊中的空間。如果插入一個值到列中,然后刪除一個值。當行需要空間的會后,數據塊會重新使用之前刪掉釋放出來的索引槽位。
索引不能合並他們自己,除非手動執行ALTER INDEX REBUILD或者COALESCE選項。
5.3 合並索引塊
索引合並壓實當前存在索引數據,如果重新組織釋放了塊,釋放的塊留在索引結構中,並不釋放出來給其他用戶。不會自動執行,需要輸入ALTER INDEX REBUILD或者COALESCE選項。