文章目录
数据页结构对于底层存储是重要的内容,可以从中了解一个数据库的架构设计和工作机制,这里我通过一些测试,对比磁盘内容的变化和相关视图信息,大体得出一些较为浅显的内容
完整数据页
首先来看一个数据页是什么样的,由于版本差异其结构体可能发生变化,大体上是下面这样
00000000 04 00 00 00 e0 27 00 00 ff ff ff ff ff ff ff ff |.....'..........|
00000010 ff ff ff ff 14 00 00 00 00 00 00 00 32 de b3 00 |............2...|
00000020 00 00 00 00 04 00 bc 00 00 00 00 00 02 00 62 00 |..............b.|
00000030 52 00 5a 00 00 00 b0 00 00 00 df 05 00 02 04 00 |R.Z.............|
00000040 00 00 02 08 00 00 fc 04 04 00 00 00 02 08 00 00 |................|
00000050 b4 04 00 00 00 00 00 00 00 00 ff ff ff ff ff ff |................|
00000060 ff ff 00 1c 00 ff ff 00 00 81 61 01 00 00 00 00 |..........a.....|
00000070 00 ff ff ff ff 7f ff ff db 85 0b 00 00 00 00 1c |................|
00000080 00 02 00 00 00 81 62 02 00 00 00 00 00 ff ff ff |......b.........|
00000090 ff 7f ff ff dc 85 0b 00 00 00 00 22 00 01 00 00 |..........."....|
000000a0 00 87 64 64 64 64 64 64 64 01 00 00 00 00 00 00 |..ddddddd.......|
000000b0 ca 9f 00 00 5b 00 ee 85 0b 00 00 00 00 00 00 00 |....[...........|
000000c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00001ff0 5a 00 7e 00 9a 00 52 00 00 00 00 00 00 00 00 00 |Z.~...R.........|
00002000
通用页头
页头部分主要包括了页的物理存储信息和类型等
00000000 04 00 00 00 e0 27 00 00 ff ff ff ff ff ff ff ff |.....'..........|
00000010 ff ff ff ff 14 00 00 00 00 00 00 00 32 de b3 00 |............2...|
00000020 00 00 00 00
其内容解析为
bit 1-2 TBS NO 4
bit 3-4 FILE NO 0
bit 5-8 PAGE NO 10208
bit 9-10 PREV FILE ID -1
bit 11-14 PREV PAGE NO -1
bit 15-16 NEXT FILE ID -1
bit 17-20 NEXT PAGE NO -1
bit 21-24 PAGE TYPE 20
bit 25-28 CHECK SUM
bit 29-36 LSN 11787826
空间页头
空间页头主要包括页内空间使用情况,便于快速定位到空闲位置和高水位
04 00 bc 00 00 00 00 00 02 00 62 00 |..............b.|
00000030 52 00 5a 00 00 00 b0 00
bit 37-38 TBS NO 4
bit 39-40 HEAP LOW 188
bit 41-42 HEAP HIGH 0
bit 43-44 UNKNOWN
bit 45-46 ROW CNT
bit 47-48 LAST FREE LIST
bit 49-56 UNKNOWN
索引页头
索引页头包含了索引相关信息,用于关联索引节点
00 00 df 05 00 02 04 00 |R.Z.............|
00000040 00 00 02 08 00 00 fc 04 04 00 00 00 02 08 00 00 |................|
00000050 b4 04 00 00 00 00 00 00 00 00 ff ff ff ff ff ff |................|
00000060 ff ff
bit 57-58 PAGE LEVEL 0
bit 59-62 INDEX_ID(OBJECT_ID) 33555935
bit 63-64 LEAF_SEGMENT_GROUP 4
bit 65-66 LEAF_SEG_FILE_ID 0
bit 67-70 LEAF_SEG_PAGE_NO 2050
bit 71-72 LEAF_SEG_OFFSET 1276
bit 73-74 INNER_SEGMENT_GROUP 4
bit 75-76 INNER_SEG_FILE_ID 0
bit 77-80 INNER_SEG_PAGE_NO 2050
bit 81-82 INNER_SEG_OFFSET 1204
bit 83-97 UNKNOWN
数据行
数据行主要包括数据内容,删除标记,ROWID等,实际内容部分由数据具体格式决定,此处我放了一个包含int和varchar(100)两个字段的行,由于被我进行过update操作,所以会包含指向回滚页信息
00 1c 00 ff ff 00 00 81 61 01 00 00 00 00 |..........a.....|
00000070 00 ff ff ff ff 7f ff ff db 85 0b 00 00 00 00 1c |................|
00000080 00 02 00 00 00 81 62 02 00 00 00 00 00 ff ff ff |......b.........|
00000090 ff 7f ff ff dc 85 0b 00 00 00
00 22 00 01 00 00 |..........."....|
000000a0 00 87 64 64 64 64 64 64 64 01 00 00 00 00 00 00 |..ddddddd.......|
000000b0 ca 9f 00 00 5b 00 ee 85 0b 00 00 00 00 00 00 00 |....[...........|
000000c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
bit 98-154 OLD DATA (INVALID)
bit 155 DELETE_FLAG 0
bit 156-157 ROWLEN 34
bit 158-161 INT4 DATA 1
bit 162-179 VARCHAR DATA ddddddd
bit 170- 176 ROWID 1
bit 177-180 FPA_PAGE_NO 40906
bit 181-182 FPA_FILE_NO 0
bit 183-184 UNKNOWN 5b 00
bit 185-187 TRXID 755182
有多行数据的时候依次向后即可
回滚页
当对于本行TRXID不满足MVCC可见性条件时,根据已经提交的版本判断合适的TRXID并向对应回滚页读取
根据信息找到前一个版本位于回滚页40906中,回滚页如下
00000000 01 00 00 00 ca 9f 00 00 ff ff ff ff ff ff ff ff |................|
00000010 ff ff ff ff 1d 00 00 00 00 00 00 00 33 de b3 00 |............3...|
00000020 00 00 00 00 ee 85 0b 00 00 00 01 37 00 ad 00 07 |...........7....|
00000030 c5 41 ad 3e 24 06 00 24 00 28 00 03 00 00 00 00 |.A.>$..$.(......|
00000040 00 00 00 00 00 00 00 00 00 00 00 16 05 00 ff ff |................|
00000050 ff ff ff ff ff 00 00 00 00 37 00 32 00 02 01 04 |.........7.2....|
00000060 00 00 00 db 85 0b 00 00 00 00 00 00 00 00 00 16 |................|
00000070 05 00 ff ff ff ff 7f ff ff 01 00 00 00 00 00 00 |................|
00000080 00 01 00 01 00 01 00 61 00 00 00 5b 00 20 00 12 |.......a...[. ..|
00000090 00 05 00 00 00 ee 85 0b 00 00 00 00 00 00 00 00 |................|
000000a0 00 00 00 00 00 00 00 00 00 00 00 8d 00 8f 90 00 |................|
000000b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00002000
由于回滚页完的具体各解法目前我还尚未研究透彻,所以有待以后研究,但目前
根据数据行中的 c9 9f 00 00 5b 00 信息是足够定位到回滚页中行修改前数据如下
c9 9f 00 00 5b 00 01 00 00 00 00 00 00 |.......[........|
00000080 00 01 00 01 00 03 00 64 64 64 00 00 00 5b 00
可以看出其中包含下列信息
ROWID 1
修改前数据 1 ddd
偏移量数组
在数据页的末尾,通过偏移量数组记录了每一行数据的起始位置,即SLOT信息
00001ff0 5a 00 7e 00 9a 00 52 00 00 00 00 00 00 00 00 00 |Z.~...R.........|
00002000
如我这里的信息为
HEAD OFFSET 0x52
SLOT1 OFFSET 0x9a
SLOT2 OFFSET 0x7e
DBMS_PAGE
在DM8中提供了DBMS_PAGE这个Package帮助通过预定义的结构体来查看页的信息,这里列举一些常见用法,详细可以根据Package内的方法灵活使用
查看通用页头
SQL> DECLARE
PAGE0 VARBINARY;
PHINFO DBMS_PAGE.PH_T;
PHINFO_ARR DBMS_PAGE.PH_ARR_T;
BEGIN
PHINFO_ARR = NEW DBMS_PAGE.PH_T[1];
DBMS_PAGE.PAGE_LOAD(4,0,10208,PAGE0);
PHINFO_ARR[1] = DBMS_PAGE.PAGE_HEAD_GET(PAGE0);
SELECT * FROM ARRAY PHINFO_ARR;
END;
/
行号 TS_ID SELF_FILE_ID SELF_PAGE_NO PREV_FILE_ID PREV_PAGE_NO NEXT_FILE_ID NEXT_PAGE_NO PAGE_TYPE CHECKSUM
---------- ----------- ------------ ------------ ------------ ------------ ------------ ------------ ----------- -----------
LSN
--------------------
1 4 0 10208 -1 -1 -1 -1 20 0
11838241
已用时间: 1.305(毫秒). 执行号:685000.
查看空间页头
SQL> DECLARE
PHINFO DBMS_PAGE.dps_t;
PHINFO_ARR DBMS_PAGE.DPS_ARR_T;
BEGIN
PHINFO_ARR = NEW DBMS_PAGE.dps_t[1];
PHINFO_ARR[1] = DBMS_PAGE.DATA_PAGE_SPACE_INFO_GET(4,0,10208);
SELECT * FROM ARRAY PHINFO_ARR;
END;
/
行号 HEAP_LOW HEAP_HIGH USED_TINYINT FREE_TINYINT USED_RATE HEAP_HIGH_LEFT FREE_LIST_SIZE FREE_LIST_RATE MAX_REC_ABLE
---------- ----------- ----------- ------------ ------------ ----------- -------------- -------------- -------------- ------------
1 346 0 374 7818 4 7818 0 0 7816
已用时间: 0.252(毫秒). 执行号:685001.
查看索引页头
SQL> DECLARE
PHINFO DBMS_PAGE.dpih_t;
PHINFO_ARR DBMS_PAGE.DPIH_ARR_T;
BEGIN
PHINFO_ARR = NEW DBMS_PAGE.dpih_t[1];
PHINFO_ARR[1] = DBMS_PAGE.data_page_ind_head_get(4,0,10208);
SELECT * FROM ARRAY PHINFO_ARR;
END;
/
行号 PAGE_LEVEL INDEX_ID LEAF_SEG_GROUP_ID LEAF_SEG_FILE_ID LEAF_SEG_PAGE_NO LEAF_SEG_OFFSET INNR_SEG_GROUP_ID INNR_SEG_FILE_ID INNR_SEG_PAGE_NO INNR_SEG_OFFSET
---------- ----------- ----------- ----------------- ---------------- ---------------- --------------- ----------------- ---------------- ---------------- ---------------
1 0 33555935 4 0 2050 1276 4 0 2050 1204
已用时间: 0.413(毫秒). 执行号:685002.
查看FREE LIST
SQL> DECLARE
PHINFO DBMS_PAGE.free_list_t;
PHINFO_ARR DBMS_PAGE.FREE_LIST_ARR_T;
BEGIN
PHINFO_ARR = NEW DBMS_PAGE.free_list_t[1];
PHINFO_ARR = DBMS_PAGE.data_page_free_list_get(4,0,10208);
SELECT * FROM ARRAY PHINFO_ARR;
END;
/
行号 OFF LEN
---------- ----------- -----------
1 98 28
已用时间: 0.413(毫秒). 执行号:685003.
总结
到此就对DM8数据页的格式做了一个浅薄的介绍,部分位还尚存疑点,需要进一步在工作和实验中进行学习和验证,欢迎了解的同学共同分享。