級別: 初級
郝慶運(yùn) (haoqingy@cn.ibm.com), 軟件工程師, IBM
黃耀華 (yaohuah@cn.ibm.com), 軟件工程師, IBM
2009 年 6 月 05 日
在本文中我們將利用 db2dart 工具來理解 DB2 數(shù)據(jù)的存儲方式,特別是 DB2 數(shù)據(jù)在每個頁中是如何存儲的。
簡介
DB2 數(shù)據(jù)庫中的數(shù)據(jù)表存放在表空間中,每個表空間可以有一個或者多個容器(Container),頁(page)是容器中最基本的存儲單元,每個頁可以存儲一定數(shù)量的記錄??墒敲恳粭l記錄在頁中的存儲是什么樣子的?有沒有什么工具能夠看到每個頁中存儲了哪幾條記錄?
db2dart 是 DB2 中自帶的一個數(shù)據(jù)庫分析利器,可以分析數(shù)據(jù)庫、表空間和表等,驗證數(shù)據(jù)庫及其對象的體系結(jié)構(gòu)是否正確,還可以使用它來顯示數(shù)據(jù)庫控制文件的內(nèi)容,以便從其他情況下可能無法訪問的表中抽取數(shù)據(jù)。
在本文中將通過 db2dart 來顯示和分析數(shù)據(jù)庫中的數(shù)據(jù),從而深入理解 DB2 的數(shù)據(jù)存儲方式,這對于提高 DBA 數(shù)據(jù)恢復(fù)技能也有一定的幫助。
DB2 中數(shù)據(jù)存儲方式概述
DB2 數(shù)據(jù)庫中有兩種類型的表空間,它們都可以在單個數(shù)據(jù)庫中使用:
- 系統(tǒng)管理的空間(SMS),操作系統(tǒng)的文件管理器控制其中的存儲空間。
- 數(shù)據(jù)庫管理的空間(DMS),數(shù)據(jù)庫管理器控制其中的存儲空間。
還可以創(chuàng)建自動存儲器表空間,該表空間將使用 SMS 或 DMS 作為基本表空間類型。數(shù)據(jù)庫管理器將根據(jù)其中包含的數(shù)據(jù)類型選擇實際類型 SMS 或 DMS(SMS 用于臨時表空間,DMS 則用于其他表空間)。
本文中我們只針對 DMS 類型的表空間進(jìn)行討論。
表空間是一種存儲結(jié)構(gòu),它包含表、索引、大對象和長型數(shù)據(jù)。它們允許將數(shù)據(jù)庫和表數(shù)據(jù)的位置直接指定到容器上。容器可以是目錄名、設(shè)備名或文件名,單個表空間可跨多個容器,如圖 1 所示。
圖 1. 數(shù)據(jù)庫中的表空間、容器和表
DB2 數(shù)據(jù)庫管理器會平衡分布在所有容器中的數(shù)據(jù)負(fù)荷,所有容器都將用于存儲數(shù)據(jù)。數(shù)據(jù)庫管理器在使用另一個容器之前寫入一個容器的頁數(shù)稱為擴(kuò)展數(shù)據(jù)塊(extent)大小。數(shù)據(jù)庫管理器并非始終從第一個容器開始存儲表數(shù)據(jù)。在圖 2 中,表空間 HUMANERS 有 4 個容器,擴(kuò)展數(shù)據(jù)庫大小為 2 頁,每個頁大小是 4K 字節(jié)。 DEPARTMENT 和 EMPLOYEE 表都有 7 頁,并且都跨越所有四個容器。
圖 2. 表空間中的容器和擴(kuò)展數(shù)據(jù)庫
那每個頁中的記錄是如何存儲的呢,接下來我們利用 db2dart 工具來更為直觀的進(jìn)行理解。
db2dart 使用簡介
工欲善其事必先利其器,那我們就先來看看 db2dart(DB2 Database Analysis and Reporting Tool)這個工具。如上文所述,db2dart 更多的是一個診斷工具,可以用來驗證數(shù)據(jù)庫以及相關(guān)的數(shù)據(jù)庫對象是否正確,是否存在問題,還可以用來顯示數(shù)據(jù)庫控制文件的內(nèi)容,以便在重建數(shù)據(jù)庫時從其他情況下無法訪問的表中抽取數(shù)據(jù)。
如果想查看 db2dart 的相關(guān)語法,可以在命令窗口(DB2CLP)中,發(fā)出 db2dart 命令(不帶任何參數(shù)),就可以看到其所有選項及其功能。在本文中我們將要用到的是:
/DD:提取格式化的表數(shù)據(jù)。
命令格式:db2dart <database name> /DD /TSI … /OI … /PS … /NP ... /V Y
|
在上面的命令中:
- /TSI 用于指定表空間 ID(tablespace ID),
- /OI 用于指定對象 ID(object ID),
- /PS 用于指定開始的數(shù)據(jù)頁,
- /NP 用于指定所要提取的數(shù)據(jù)頁的數(shù)量,
- /V 用于設(shè)定是否顯示詳細(xì)信息,Y:顯示,N:不顯示。
這里的表空間 ID 和對象 ID 可以從 CATALOG 表 SYSCAT.TABLES 中獲取,下文中將給出具體的 SQL 語句。此外還可以使用 /RPTN 指定用來保存結(jié)果的文件名。
注意,db2dart 不能在仍具有活動連接的數(shù)據(jù)庫上運(yùn)行。如果存在活動連接,db2dart 將輸出警告信息,而且有可能輸出錯誤的結(jié)果??梢酝ㄟ^“ FORCE APPLICATIONS ALL ”命令斷開所有的數(shù)據(jù)庫連接。也正是因為這一離線工作的特性,使得 db2dart 在數(shù)據(jù)庫崩潰之后的恢復(fù)中能夠發(fā)揮巨大的作用。
準(zhǔn)備工作
在開始之前,我們先創(chuàng)建一個新的數(shù)據(jù)庫名字叫做 MYDB,如清單 1 所示。當(dāng)然用已經(jīng)存在的數(shù)據(jù)庫也可以,但是為了能夠簡化環(huán)境,清楚的、逐步的進(jìn)行我們接下來的討論,建議使用一個全新的數(shù)據(jù)庫。
本文中所有操作都可在 LinuxAMD64 平臺上的 DB2 V95 及之后的版本進(jìn)行,若其他數(shù)據(jù)庫版本或者其他平臺,輸出結(jié)果可能稍微有所差別。
清單 1. 創(chuàng)建數(shù)據(jù)庫
創(chuàng)建數(shù)據(jù)庫之后我們檢查一下表空間的情況,使用的命令及結(jié)果如清單 2 所示。
清單 2. 查看表空間
bash-3.1$ db2 list tablespaces
Tablespaces for Current Database
Tablespace ID = 0
Name = SYSCATSPACE
Type = Database managed space
Contents = All permanent data. Regular table space.
State = 0x0000
Detailed explanation:
Normal
Tablespace ID = 1
Name = TEMPSPACE1
Type = System managed space
Contents = System Temporary data
State = 0x0000
Detailed explanation:
Normal
Tablespace ID = 2
Name = USERSPACE1
Type = Database managed space
Contents = All permanent data. Large table space.
State = 0x0000
Detailed explanation:
Normal
|
這三個表空間是創(chuàng)建數(shù)據(jù)庫時默認(rèn)創(chuàng)建的,其中表空間 USERSPACE1 用來保存永久性數(shù)據(jù),當(dāng)我們創(chuàng)建新表時 USERSPACE1 將是默認(rèn)的表空間。我們也可以創(chuàng)建新的表空間并且在創(chuàng)建新表時指定特定的表空間,但在本文中我們將一直使用 USERSPACE1 。
需要特別指出的是,USERSPACE1 的類型是 Database managed space(DMS)即數(shù)據(jù)庫管理空間表空間,與之相對的是 System managed space(SMS,系統(tǒng)管理空間),至于二者的區(qū)別在此不進(jìn)行解釋,讀者可以從參考資源部分的“ DB2 信息中心”找到相關(guān)內(nèi)容。
接下來我們看一下表空間 USERSPACE1 的一些細(xì)節(jié)信息,在我們接下來的討論中將會與用到這些信息。使用的命令及結(jié)果如清單 3 所示。
清單 3. 查看表空間 USERSPACE1 詳情
bash-3.1$ db2 list tablespaces show detail
Tablespaces for Current Database
// 此處刪除若干行
Tablespace ID = 2
Name = USERSPACE1
Type = Database managed space
Contents = All permanent data. Large table space.
State = 0x0000
Detailed explanation:
Normal
Total pages = 256
Useable pages = 224
Used pages = 96
Free pages = 128
High water mark (pages)
= 96
Page size (bytes)
= 4096
Extent size (pages)
= 32
Prefetch size (pages)
= 32
Number of containers
= 1
|
表空間是一個頁集(page set),頁(page)是 DB2 中表空間、索引空間或虛擬內(nèi)存中的存儲單元,多數(shù)情況下在表空間中頁可包含表的一行或多行。在清單 3 中我們可以看到,這個表空間一共有 256 個頁(Total pages = 256),可以用的是 224 個頁(Useable pages = 224),已用了 96 個頁,空閑的 128 個頁。除此之外的那 32 個頁(256 - 224)是被 DB2 用作了某種開銷。
每個頁的大小是 4096 bytes(Page size (bytes) = 4096),這樣我們可以計算出這個表空間的大小是:4096 bytes * 256 = 1 MB,這個表空間雖然比較小,但對于我們接下來的操作和討論已經(jīng)足夠了。
利用 db2dart 來看空的表
創(chuàng)建一個簡單的關(guān)系型表 TB1,并獲取這個表的表空間 ID 和對象 ID,在下文中我們將多次使用這對 ID 作為 db2dart 的輸入。使用的 SQL 以及結(jié)果如清單 4 所示。
清單 4. 創(chuàng)建表
CREATE TABLE TB1(s1 SMALLINT, v1 VARCHAR(256))
SELECT SUBSTR(TABNAME,1,30) TABNAME, TABLEID,TBSPACEID
FROM SYSCAT.TABLES WHERE TABNAME='TB1'
TABNAME TABLEID TBSPACEID
----------------------- ------- ---------
TB1 4
2
1 record(s) selected.
|
現(xiàn)在我們已經(jīng)創(chuàng)建了一個關(guān)系型表 TB1,尚未插入任何的數(shù)據(jù),我們使用 db2dart 來提取表數(shù)據(jù),來看看一個空表中的信息,同時熟悉一下 db2dart 的使用。這里我們用的是 /DD 操作,用 /TSI 2 和 /OI 4 來指定表 TB1,從第 0 頁開始提取,一共提取 100 頁。為什么我們要提取 100 頁而不是其他的數(shù)量呢?沒有關(guān)系,在第一次使用該命令時我們可以選擇任意數(shù)量,然后根據(jù)得到的報告以及之后的需求來調(diào)整這個數(shù)量,事實上在這里我們完全可以使用一個很小的數(shù)字,因為我們面對的是一個空表。使用的命令以及輸出如清單 5 所示。
清單 5. 使用 db2dart 提取空表信息
bash-3.1$ db2 connect reset
DB20000I The SQL command completed successfully.
bash-3.1$ db2dart mydb /DD /TSI 2 /OI 4 /PS 0 /NP 100 /V Y /RPTN MYDB.RPT_TB1_empty
____________________________________________________________________
_____ D B 2 D A R T _____
Database Analysis Tool
I B M
DB2 6000
The DB2DART Tool is a utility for the analysis of databases,
tablespaces, and tables. DART's primary function is to
examine databases for their architectural correctness, and to
report any encountered errors.
____________________________________________________________________
______________________________________________________________________
_______ DART _______
D a t a b a s e A n a l y s i s a n d R e p o r t i n g T o o l
IBM DB2 6000
______________________________________________________________________
DART (V9.5) Report:
2009-03-11-07.45.34.651415
Database Name: D
Report name: D.RPT_TB1_empty
Database Subdirectory: /work1/haoqingy/haoqingy/NODE0000/SQL00001
Operational Mode: Database Inspection Only (INSPECT)
______________________________________________________________________
----------------------------------------------------------------------
Connecting to Buffer Pool Services...
Table object report phase start.
Formatted data being dumped to report...
Dump format is verbose.
Dumping...
Dumping...
Table object report phase end.
______________________________________
The requested DB2DART processing has completed successfully!
All operation completed without error;
no problems were detected in the database.
______________________________________
Complete DB2DART report found in: MYDB.RPT_TB1_empty
_______ D A R T P R O C E S S I N G C O M P L E T E _______
|
接下來我們較為詳細(xì)的討論 db2dart 得到的報告,存放在下載部分的文件 MYDB.RPT_TB1_empty 中。如果我們沒有指定 /RPTN 參數(shù),默認(rèn)的報告存放在 MYDB.RPT 即數(shù)據(jù)庫名字加上 .RPT 的后綴。報告的內(nèi)容如清單 6 所示(為便于閱讀刪除了部分信息以及空行)
清單 6. 使用 db2dart 提取空表信息所生成的報告
______________________________________________________________________
_______ DART
_______
D a t a b a s e A n a l y s i s a n d R e p o r t i n g T o o l
IBM DB2 6000
______________________________________________________________________
DART (V9.5) Report:
2009-03-10-23.43.32.808469
Database Name: MYDB
Report name: MYDB.RPT_TB1_empty
Database Subdirectory: /work1/haoqingy/haoqingy/NODE0000/SQL00001
Operational Mode: Database Inspection Only (INSPECT)
______________________________________________________________________
----------------------------------------------------------------------
Action option: DD
Table-object-ID: 4; Tablespace-ID: 2; First-page: 0; Number-pages: 100; Verbose: y
Connecting to Buffer Pool Services...
Table object report phase start.
Dump format is verbose.
______________________________________
Page 0 of object 4 from table space 2.
BPS Page Header:
Page Data Offset = 48
Page Data Length = 4048
Page LSN = 000000000234041A
Object Page Number = 0
Pool Page Number = 128
Object ID = 4
Object Type = Data Object
Data Page Header:
Slot Count = 4
Total Free Space = 2884
Total Reserve Space = 0
Youngest Reserve Space = n/a
Youngest TID = n/a
Free Space Offset = 2891
Maximum Record Size = 0
Data Records:
Slot 0:
Offset Location = 3996 (xF9C)
Record Length = 32 (x20)
Record Type = Data Object Header Control Record
Page count = 1
Object Creation LSN = 000000000234041A
Object State = x0000
UDI Since Runstats = 0
DFH flag bits = x00000000
Row Change Timestamp = x00000000000000
Slot 1:
Offset Location = 2992 (xBB0)
Record Length = 1004 (x3EC)
Record Type = Free Space Control Record
Free space entries:
0: 2884 (x0B44), 4028 (x0FBC), 4028 (x0FBC), 4028 (x0FBC)
4: 4028 (x0FBC), 4028 (x0FBC), 4028 (x0FBC), 4028 (x0FBC)
8: 4028 (x0FBC), 4028 (x0FBC), 4028 (x0FBC), 4028 (x0FBC)
12: … .. 此處刪除若干行
492: 4028 (x0FBC), 4028 (x0FBC), 4028 (x0FBC), 4028 (x0FBC)
496: 4028 (x0FBC), 4028 (x0FBC), 4028 (x0FBC), 4028 (x0FBC)
Slot 2:
Offset Location = 2916 (xB64)
Record Length = 76 (x4C)
Record Type = Table Directory Record
TDIR version = 2
MetaIndex Does Not Exist
Max Insert Search = 0
Dictionary RID -- Page 0 Slot 0
Mapping Directory RID -- Page 0 Slot 0
Current table row format version = 0
Flags = x0000000106000000
bit representation = 00000000 00000000 00000000 00000001
00000110 00000000 00000000 00000000
Check pending info:
Constraint status = x00
Constraint RID page = 0
last BID page = x00000000
Slot 3:
Offset Location = 2892 (xB4C)
Record Length = 24 (x18)
Record Type = Table Description Record
Number of Columns = 2
Column 1:
Type is Small Integer
Length = 2
Allows NULLs
Prohibits Default
Fixed offset: 0
Column 2:
Type is Variable Length Character String
Maximum Length = 256
Allows NULLs
Prohibits Default
Fixed offset: 3
Slots Summary: Total=4, In-use=4, Deleted=0.
Table object report phase end.
______________________________________
The requested DB2DART processing has completed successfully!
All operation completed without error;
no problems were detected in the database.
______________________________________
Complete DB2DART report found in: MYDB.RPT_TB1_empty
_______ D A R T P R O C E S S I N G C O M P L E T E _______
|
在這個報告中,我們只看到了這個表的 page 0,這是因為其他的頁當(dāng)前都是空的,所以 db2dart 沒有進(jìn)行提取,而且如果我們 /NP 的值改為 1 也可以得到相同的結(jié)果。在 page 0 首先是一個記錄相關(guān)信息的 page header,接著又分成了 4 個 slot,slot 是 page 中通過偏移(offset)劃分出來的更小的不規(guī)則的存儲空間。
- slot 0 中的記錄是 Data Object Header Control Record,用來記錄一些數(shù)據(jù)對象(表)的控制信息;
- slot 1 中的記錄是 Free Space Control Record 即 FSCR,用來記錄接下來 500 個頁中每個頁的可用空間近似值;
- slot 2 中的記錄是 Table Directory Record,用來記錄這個表(TB1)的目錄信息;
- slot 3 中的記錄是 Table Description Record 即對這個表的描述,這里可以看到這個表有多少列(Number of Columns = 2),第一列的類型是 Small Integer,長度是 2,允許為空,沒有默認(rèn)值,第二列的類型是 Variable Length Character String,長度為 256,允許為空,沒有默認(rèn)值。這與我們之前創(chuàng)建表 TB1 的語句(CREATE TABLE TB1(s1 SMALLINT, v1 VARCHAR(256)))是完全一致的。
需要指出的是,并非每一個 page 的前 4 個 slot 都是以上內(nèi)容,我們當(dāng)前看的是這個表對象的第一個頁即 page 0,所以在這個 page 中記錄這個表的相關(guān)信息,此外 FSCR 會在第 501 個 page 中再次出現(xiàn)用來記錄從 501 頁到 1000 頁的每個頁的可用空間近似值。
利用 db2dart 來看 DB2 數(shù)據(jù)
插入一條記錄再利用 db2dart 來看
我們已經(jīng)討論過了一個空的表中結(jié)構(gòu)和信息,接下來看用戶插入的數(shù)據(jù)是如何存儲的,為了便于更加清晰的看到用戶數(shù)據(jù),我們先只插入一條記錄然后用 db2dart /DD 來看。使用的命令如清單 7 所示。
清單 7. 插入一條記錄然后用 db2dart 來提取
db2 “ insert into tb1 values(123,'abc') ”
db2 force applications all
db2dart MYDB /DD /TSI 2 /OI 4 /PS 0 /NP 100 /V Y /RPTN MYDB.RPT_TB1_1Row
|
在下載部分的報告文件 MYDB.RPT_TB1_1Row 中可以看到,其內(nèi)容與清單 6 相似,在此不需要展示其全部內(nèi)容,差別在于 BPS Page Header 中的一些數(shù)值發(fā)生變化,如 slot Count,Total Free Space 等,以及出現(xiàn)了一個新的 slot 4,如清單 8 所示。
清單 8. 用 db2dart 看到的新插入的行
Slot 4:
Offset Location = 2873 (xB39)
Record Length = 19 (x13)
Record Type = Table Data Record (FIXEDVAR) (PUNC)
Record Flags = 0
Fixed part length value = 8
Column 1:
Fixed offset: 0
Type is Small Integer
Value = 123
Column 2:
Fixed offset: 3
Type is Variable Length Character String
Length = 3 Offset = 8
616263
abc
|
在 slot 4 中存放的記錄是 Table Data Record,也就是真正的用戶數(shù)據(jù),可以看到第一列(column 1)的值是 123(value=123),第二列的值是 616263 即 abc,這正是我們之前所插入的記錄。那插入的每條記錄分別對應(yīng)一個 slot 呢還是多條記錄可以存放在同一個 slot 中呢,我們接下來繼續(xù)討論。
插入多條記錄再利用 db2dart 來看
向表 TB1 中插入多條記錄,然后使用 db2dart /DD 來提取,并將報告保存在下載部分的 MYDB.RPT_TB1_10Row 文件中,使用的 SQL 語句以及命令如清單 9 所示。
清單 9. 插入多條記錄
db2 connect to mydb
db2 "insert into tb1 values(1231,'abc1')"
db2 "insert into tb1 values(1232,'abc2')"
db2 "insert into tb1 values(1233,'abc3')"
db2 "insert into tb1 values(1234,'abc4')"
db2 "insert into tb1 values(1235,'abc5')"
db2 "insert into tb1 values(1236,'abc6')"
db2 "insert into tb1 values(1237,'abc7')"
db2 "insert into tb1 values(1238,'abc8')"
db2 "insert into tb1 values(1239,'abc9')"
db2 connect reset
db2 force applications all
db2dart MYDB /DD /TSI 2 /OI 4 /PS 0 /NP 100 /V Y /RPTN MYDB.RPT_TB1_10Row
|
在文件 MYDB.RPT_TB1_10Row 中可以看到,新插入的每一條記錄分別對應(yīng)著一個 slot,即從 slot 5 到 slot 13 。而且我們注意到所有的這些 slot 都仍然在 page 0 中,那么一個頁究竟能分成多少個 slot(即存放多少條記錄)呢?我們下面對這個問題進(jìn)行討論。
我們從清單 6 中提取一些信息出來,如清單 10 所示。
清單 10. slot 的偏移位置和記錄長度
Page 0 of object 4 from table space 2.
BPS Page Header:
Page Data Offset = 48
Page Data Length = 4048
Slot 0:
Offset Location = 3996 (xF9C)
Record Length = 32 (x20)
Slot 1:
Offset Location = 2992 (xBB0)
Record Length = 1004 (x3EC)
Slot 2:
Offset Location = 2916 (xB64)
Record Length = 76 (x4C)
Slot 3:
Offset Location = 2892 (xB4C)
Record Length = 24 (x18)
|
我們保留了每一個 slot 的兩個數(shù)字,并且發(fā)現(xiàn)它們之間的關(guān)系:
3996 – 2992 = 1004 ;
2992 – 2916 = 76 ;
2916 – 2892 = 24 ;
|
可以看出,存儲這些 slot 是從 page 的尾部開始,后來的 slot 接著前一個 slot 的位置進(jìn)行存放,并用上一個 slot 的偏移位置減去自身的長度(record length)作為自己的偏移位置,如圖 3 所示。
圖 3. page 中的 slot
每一個 slot 的長度由這條記錄的數(shù)據(jù)的長度和保存 slot 信息的固定長度組成,由于數(shù)據(jù)的長度是可變的所以每個 slot 的長度是不固定的,例如 slot 4 的長度是 19 字節(jié),而 slot 5 到 slot 13 的長度是 20 字節(jié)。當(dāng) page 中沒有足夠的空閑空間分配給下一個 slot 時,DB2 將使用下一個 page 。我們接下來對此進(jìn)行驗證。
page 0 什么時候用完?
用清單 11 中的命令向表 TB1 中插入 10 條記錄,每條記錄長度較長,然后用 db2dart /DD 提取,將結(jié)果保存在下載部分的 MYDB.RPT_TB1_10LongRow 文件中。從該文件中我們可以看到,所有的記錄仍然在 page 0 當(dāng)中。
清單 11. slot 的偏移位置和記錄長度
db2 connect to mydb
db2 "insert into tb1 values(1230,'abc0tttttttttttttttttttttttttttttttttttt
ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt
ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt
ttttttttttt')"
db2 "insert into tb1 values(1231,'abc1tttttttttttttttttttttttttttttttttttt
ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt
ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt
ttttttttttt')"
db2 "insert into tb1 values(1232,'abc2ttttttttttttttttttttttttttttttttttttt
ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt
ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt
ttttttttttt')"
// 反復(fù)執(zhí)行上一條語句 7 次,共插入 10 條記錄
db2 force applications all
db2dart mydb /DD /TSI 2 /OI 4 /PS 0 /NP 100 /V Y /RPTN MYDB.RPT_TB1_10LongRow
|
我們再一次利用清單 11 中的命令向表中再插入 10 條記錄,然后將 db2dart /DD 的結(jié)果保存到下載部分 MYDB.RPT_TB1_20LongRow 文件中。在這個結(jié)果中我們可以看到,這 10 條記錄全部被存放在 page 1 上,也就是說 page 0 已經(jīng)沒有足夠的空間存放其中的任何一條記錄。在 page 1 中的 slot 0 到 slot 4 存放的是我們剛才插入的前四條記錄,這與 page 0 中存放的特殊用途的記錄(見清單 6)不同。
page 0 真的滿了嗎?
需要注意的是,并不能說只有當(dāng)前頁完全用完才會啟用新的頁,例如當(dāng)前空閑空間還有 100 字節(jié),而下一個 slot 的長度有 101 字節(jié),那么這個 slot 將被放到下一個 page 中,在此之后用戶又插入一個長度只有 10 字節(jié)的記錄,那么存放這條記錄的 slot 仍然可以在前一個 page 中分配。現(xiàn)在我們來驗證 page 0 中是否還能夠存放新的記錄。從 page 0 的 page header 中可以看到還有 135 字節(jié)的空閑空間(Total Free Space = 135),此時向表中插入一條較短的記錄,然后將 db2dart /DD 的結(jié)果保存在下載部分的 MYDB.RPT_TB1_1MoreRow 文件中,使用的命令如清單 12 所示。在這個結(jié)果中我們可以看到,新的記錄被存放到 page 0 的 slot 24 中,這就說明 page 0 中還可以繼續(xù)存放新的記錄。
清單 12. 插入一條較短的記錄
db2 connect to mydb
db2 "insert into tb1 values(9999,'aaaa')"
db2 force applications all
db2dart mydb /DD /TSI 2 /OI 4 /PS 0 /NP 100 /V Y /RPTN MYDB.RPT_TB1_1MoreRow
|
我們可以繼續(xù)向表中插入這種較短的記錄,或者空記錄(NULL)直到 page 0 再也無法存放任何記錄。那是不是說一定要等到當(dāng)前頁沒有足夠的空間時才會寫入下一頁呢?不是的。我們可以在創(chuàng)建表的時候指定 PCTFREE 選項,用來設(shè)定每個頁至少保留的空閑空間比例,當(dāng)空閑空間達(dá)到這個比例時新的記錄將不再寫入這個頁。每個頁的第一條記錄不受此限制。這個值可以設(shè)定在 0-99 任意一個數(shù)字,-1 表示默認(rèn)值,默認(rèn)的值為 0 。我們把這些留給讀者去驗證。
總結(jié)
在文中我們利用 db2dart 工具真切的看到了數(shù)據(jù)在 DB2 數(shù)據(jù)庫中是如何存儲的,存儲空間在每個頁上是如何分配的。本文僅限于 insert 了簡單數(shù)據(jù)的情況,算是拋磚引玉,讀者可以繼續(xù)利用 db2dart 工具探討 update、delete 等操作之后數(shù)據(jù)存儲發(fā)生了什么變化,也可以探討 pureXML 中的 XML 文檔的存儲。