0
点赞
收藏
分享

微信扫一扫

DM8 数据寻址测试

荷一居茶生活 2022-04-08 阅读 80
dba

文章目录

对于一张表的数据,数据库时是如何寻址并读取到数据的呢,针对DM8默认的IOT表来看看


一点题外话

PK_WITH_CLUSTER = 0                   

这个参数决定我们的PK是作为聚集主键来替代了ROWID作为数据组织标准,亦或是作为一个普通二级索引
为0时表按ROWID顺序进行聚集,PK作为二级索引,其中记录KEY和ROWID进行关联
为1时表按PK键值进行聚集,PK本身即为聚集主键,其他二级索引中记录KEY和PK KEY来进行关联

进入正题

测试程序原型

[root@dm8host7 demo]# ./dm_dpi_full 
connect to server success!
create table dpitest(userid integer,uname varchar2(100),udate date,udatetime timestamp(6),ufloat float,udecimal number(12,4),utext long,uclob clob,ubyte bfile,ublob blob,constraint dpitest_pk primary key(userid)) 
create or replace directory KNIGHTDIR as '/home/DM8_NEW/drivers/dpi/demo';
insert into dpitest(userid,uname,udate,udatetime,ufloat,udecimal,utext,uclob,ubyte,ublob) values(?,?,?,?,?,?,?,?,?,?)
Rows Affected:1
select userid,uname,udate,udatetime,ufloat,udecimal,utext,uclob,ubyte,ublob from dpitest
Column Number:10
Name:USERID	Type:7	Name:USERID	Length:10	Scale:0	Nullable:0
Name:UNAME	Type:2	Name:UNAME	Length:100	Scale:0	Nullable:1
Name:UDATE	Type:14	Name:UDATE	Length:10	Scale:0	Nullable:1
Name:UDATETIME	Type:16	Name:UDATETIME	Length:26	Scale:6	Nullable:1
Name:UFLOAT	Type:11	Name:UFLOAT	Length:53	Scale:0	Nullable:1
Name:UDECIMAL	Type:9	Name:UDECIMAL	Length:12	Scale:4	Nullable:1
Name:UTEXT	Type:19	Name:UTEXT	Length:2147483647	Scale:0	Nullable:1
Name:UCLOB	Type:19	Name:UCLOB	Length:2147483647	Scale:0	Nullable:1
Name:UBYTE	Type:1000	Name:UBYTE	Length:512	Scale:0	Nullable:1
Name:UBLOB	Type:12	Name:UBLOB	Length:2147483647	Scale:0	Nullable:1

666
卡布达
1986-10-7
1986-10-7 12:12:43.423000
412.309998
31412.311000
Row Count:1

查询segment header信息

要找到数据的物理位置,首先需要确定其segment header位置,

SQL> select b.id TBSID,a.HEADER_FILE,a.HEADER_BLOCK 
from dba_segments a,v$tablespace b 
where segment_name = 'DPITEST' 
and a.tablespace_name=b.name;

行号     TBSID       HEADER_FILE HEADER_BLOCK
---------- ----------- ----------- ------------
1          4           0           336

检测记录数

该表的segment header存储在 4号TBS, 0号FILE 的PAGE 336中
可以通过DBMS_PAGE这个Package来查看一下该PAGE的信息,这里我将向后一定范围的页一起做了检测

DECLARE
HEAD DBMS_PAGE.DPH_T;
INFO dbms_page.REC_ARR_T;
PN int;
BASEN int = 336;    //起始地址
BEGIN
for i in 0..100 loop   //检测数量
   begin
      DBMS_PAGE.DATA_PAGE_HEAD_LOAD(4,0,BASEN+i,HEAD);
      print 'PAGE_NO:'||BASEN+i||' RECORD NUMBER:'||HEAD.N_REC;
    exception
       when OTHERS then NULL;
    end;
end loop;
END;


PAGE_NO:336 RECORD NUMBER:1
PAGE_NO:337 RECORD NUMBER:0
PAGE_NO:352 RECORD NUMBER:1
PAGE_NO:353 RECORD NUMBER:0

DMSQL 过程已成功完成
已用时间: 1.154(毫秒). 执行号:1404.

对象分析

由于测试库是空库,实际上我们找到了2个对象都和之前的操作有关,那么具体是什么呢

SQL> select OBJECT_ID,INDEX_NAME,INDEX_TYPE,OBJECT_TYPE,INDEX_TYPE,UNIQUENESS from dba_indexes a,dba_objects b where TABLE_NAME='DPITEST' and a.INDEX_NAME=B.OBJECT_NAME;

行号     OBJECT_ID INDEX_NAME    INDEX_TYPE OBJECT_TYPE INDEX_TYPE UNIQUENESS
---------- --------- ------------- ---------- ----------- ---------- ----------
1          33555579  INDEX33555839 NORMAL     INDEX       NORMAL     UNIQUE
2          33555578  INDEX33555838 CLUSTER    INDEX       CLUSTER    NONUNIQUE

已用时间: 50.359(毫秒). 执行号:76701.

SQL> select * from v$segmentinfo where index_id=33555578
union all 
select * from v$segmentinfo where index_id=335555792   3   ;

行号     INDEX_ID    SEG_ID      LOGIC_PAGE_NO PHY_PAGE_NO PHY_FIRST_PAGE_IN_EXTENT FIL_ID      USE_BYTES            FREE_BYTES          
---------- ----------- ----------- ------------- ----------- ------------------------ ----------- -------------------- --------------------
1          33555578    2415        0             336         336                      0           260                  7932
2          33555579    2417        0             352         352                      0           131                  8061

已用时间: 1.242(毫秒). 执行号:1407.

由于表数据本身其实即为IOT的LEAF,所以上面检测到的对象一个是CLUSTER INDEX,另一个INDEX是我建立PK带入的二级索引

获取行数据(IOT LEAF)信息

查看具体数据在页面内部存放的偏移量和长度

SQL> DECLARE
HEAD DBMS_PAGE.DPH_T;
INFO dbms_page.REC_ARR_T;
BASN int = 336;
TBSN int = 4;
FILN int = 0;

BEGIN
    for i in 0..10 loop
        begin
        DBMS_PAGE.DATA_PAGE_HEAD_LOAD(TBSN,FILN,BASN,HEAD);
        if(HEAD.N_REC)>0 then
           a[i] = BASN;
           print 'PAGE_NO:'||BASN||' RECORD NUMBER:'||HEAD.N_REC;
           INFO = NEW dbms_page.REC_T[HEAD.N_REC];
           FOR J IN 1..HEAD.N_REC LOOP
               DBMS_PAGE.DATA_PAGE_REC_BY_SLOT_NO_LOAD(TBSN ,FILN,BASN,J,INFO[J]);
           END LOOP;
           SELECT * FROM ARRAY INFO;
        end if;
        exception
           when OTHERS then NULL;
        end;
   BASN = BASN +i;
   end loop;
END;
 /

PAGE_NO:336 RECORD NUMBER:1


行号     SLOT_NO     OFFSET      LEN         IS_DEL      TRX_ID               CLU_ROWID            ROLL_ADDR_FILE ROLL_ADDR_PAGE ROLL_ADDR_OFF
---------- ----------- ----------- ----------- ----------- -------------------- -------------------- -------------- -------------- -------------
1          1           98          148         0           22108                1                    NULL           NULL           NULL

已用时间: 1.714(毫秒). 执行号:1414.

这里通过数据页头,就可以根据SLOT_NO获取到实际数据起始位置和长度信息了

导出行数据(IOT LEAF)

直接dd出来看具体内容

[root@dm8host7 /]#  dd if=/home/DM8/data/DAMENG/MAIN.DBF of=/tmp/test.tmp bs=8192 skip=336 count=1 
1+0 records in
1+0 records out
8192 bytes (8.2 kB) copied, 0.000169785 s, 48.2 MB/s

此处不考虑平台字字节序问题,Linux默认小端,通过-C来统一输出得到如下结果

[root@dm8host7 tmp]# hexdump -C test.tmp 
00000000  04 00 00 00 50 01 00 00  ff ff ff ff ff ff ff ff  |....P...........|
00000010  ff ff ff ff 14 00 00 00  00 00 00 00 a9 57 01 00  |.............W..|
00000020  00 00 00 00 03 00 f6 00  00 00 00 00 01 00 ff ff  |................|
00000030  52 00 5a 00 00 00 04 01  00 00 7a 04 00 02 04 00  |R.Z.......z.....|
00000040  00 00 08 00 00 00 c4 09  04 00 00 00 08 00 00 00  |................|
00000050  7c 09 00 00 00 00 00 00  00 00 ff ff ff ff ff ff  ||...............|
00000060  ff ff 00 94 00 00 00 9a  02 00 00 6c 87 08 6c 87  |...........l..l.|
00000070  08 77 5f 4f 03 00 ae 47  e1 7a 14 ae f3 3f 89 e5  |.w_O...G.z...?..|
00000080  8d a1 e5 b8 83 e8 be be  86 c3 04 0f 0d 20 0b 95  |............. ..|
00000090  02 47 02 00 00 00 00 00  00 dc 09 00 00 04 00 00  |.G..............|
000000a0  00 46 01 00 00 95 02 49  02 00 00 00 00 00 00 7f  |.F.....I........|
000000b0  3a 0a 00 04 00 00 00 47  01 00 00 91 4b 4e 49 47  |:......G....KNIG|
000000c0  48 54 44 49 52 3a 63 61  74 2e 6a 70 67 95 02 4b  |HTDIR:cat.jpg..K|
000000d0  02 00 00 00 00 00 00 ed  bf 00 00 04 00 00 00 bc  |................|
000000e0  01 00 00 01 00 00 00 00  00 00 ef 02 00 00 c9 02  |................|
000000f0  be 57 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |.W..............|
00000100  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00001ff0  00 00 5a 00 62 00 52 00  00 00 00 00 00 00 00 00  |..Z.b.R.........|
00002000

读取行数据

页的尾部会存储偏移量数组,用于定位SLOT的OFFSET,比如我这里只有一行,是从第98个字节开始,在行开始的第一个字节为删除标记,接下来两个字节会记录本行数据总长度,比如我这里为148,之后是依次记录的数据信息,最后还会包含ROWID ROLLPTR TRXID等信息,比如我这里的 trxid为22462,具体可以参考我的另一篇关于数据页格式的博文

行内数据解析

根据起始位置offset 98 换算为16进制的地址0x00000062和长度148字节,就可以得到完整的磁盘数据,对于部分字段类型解析方法可以参考我的另一篇关于数据类型表达格式的博文,在此也就不重复说明了

行外数据解析

对于LOB等外部存储的类型,会通过行内记录的元数据信息来进行二次读取,这里以数据中一个TEXT/LONG类型为例简单说明
从上面的dd数据种可以看到该字段的数据16进制存储为
02 47 02 00 00 00 00 00 00 dc 09 00 00 04 00 00 00 46 01 00 00
95 02 49 02 00 00 00 00 00 00 未知 与 dump数据不对应,可能为压缩存储格式

利用这些已知信息就可以定位到LOB数据内容

[root@dm8host7 tmp]# dd if=/home/DM8/data/DAMENG/MAIN.DBF of=/tmp/test.tmp bs=8192 skip=326 count=1 
1+0 records in
1+0 records out
8192 bytes (8.2 kB) copied, 0.000294614 s, 27.8 MB/s
[root@dm8host7 tmp]# hexdump -C test.tmp 
00000000  04 00 00 00 46 01 00 00  00 00 41 01 00 00 ff ff  |....F.....A.....|
00000010  ff ff ff ff 22 00 00 00  00 00 00 00 bc 0d 01 00  |...."...........|
00000020  00 00 00 00 03 00 5a 1a  00 00 00 00 01 00 4c 0a  |......Z.......L.|
00000030  52 00 5a 00 00 00 5a 0a  00 00 00 00 00 00 00 00  |R.Z...Z.........|
00000040  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000050  00 00 00 00 00 00 00 00  00 00 ff ff ff ff ff ff  |................|
00000060  ff ff 09 ea 47 02 00 00  00 00 00 00 dc 09 dc 09  |....G...........|
00000070  72 6f 6f 74 3a 78 3a 30  3a 30 3a 72 6f 6f 74 3a  |root:x:0:0:root:|
00000080  2f 72 6f 6f 74 3a 2f 62  69 6e 2f 62 61 73 68 0a  |/root:/bin/bash.|
00000090  62 69 6e 3a 78 3a 31 3a  31 3a 62 69 6e 3a 2f 62  |bin:x:1:1:bin:/b|
000000a0  69 6e 3a 2f 73 62 69 6e  2f 6e 6f 6c 6f 67 69 6e  |in:/sbin/nologin|
000000b0  0a 64 61 65 6d 6f 6e 3a  78 3a 32 3a 32 3a 64 61  |.daemon:x:2:2:da|
000000c0  65 6d 6f 6e 3a 2f 73 62  69 6e 3a 2f 73 62 69 6e  |emon:/sbin:/sbin|
000000d0  2f 6e 6f 6c 6f 67 69 6e  0a 61 64 6d 3a 78 3a 33  |/nologin.adm:x:3|
000000e0  3a 34 3a 61 64 6d 3a 2f  76 61 72 2f 61 64 6d 3a  |:4:adm:/var/adm:|
000000f0  2f 73 62 69 6e 2f 6e 6f  6c 6f 67 69 6e 0a 6c 70  |/sbin/nologin.lp|
00000100  3a 78 3a 34 3a 37 3a 6c  70 3a 2f 76 61 72 2f 73 
......

到此如果我们只是全LEAF扫描,这样就可以得到数据了,那么如果是通过二级索引INDEX KEY来扫描呢

获取二级索引数据信息

DECLARE
HEAD DBMS_PAGE.DPH_T;
INFO dbms_page.REC_ARR_T;
BASN int = 352;
TBSN int = 4;
FILN int = 0;

BEGIN
    for i in 0..10 loop
        begin
        DBMS_PAGE.DATA_PAGE_HEAD_LOAD(TBSN,FILN,BASN,HEAD);
        if(HEAD.N_REC)>0 then
           a[i] = BASN;
           print 'PAGE_NO:'||BASN||' RECORD NUMBER:'||HEAD.N_REC;
           INFO = NEW dbms_page.REC_T[HEAD.N_REC];
           FOR J IN 1..HEAD.N_REC LOOP
               DBMS_PAGE.DATA_PAGE_REC_BY_SLOT_NO_LOAD(TBSN ,FILN,BASN,J,INFO[J]);
           END LOOP;
           SELECT * FROM ARRAY INFO;
        end if;
        exception
           when OTHERS then NULL;
        end;
   BASN = BASN +i;
   end loop;
END;
/
行号     SLOT_NO     OFFSET      LEN         IS_DEL      TRX_ID               CLU_ROWID            ROLL_ADDR_FILE ROLL_ADDR_PAGE ROLL_ADDR_OFF
---------- ----------- ----------- ----------- ----------- -------------------- -------------------- -------------- -------------- -------------
1          1           98          19          0           22108                NULL                 0              1              0

已用时间: 1.246(毫秒). 执行号:1612.

导出二级索引数据

导出索引页中数据

[root@dm8host7 tmp]#  dd if=/home/DM8/data/DAMENG/MAIN.DBF of=/tmp/test.tmp bs=8192 skip=352 count=1 
1+0 records in
1+0 records out
8192 bytes (8.2 kB) copied, 0.00032188 s, 25.5 MB/s

[root@dm8host7 tmp]# hexdump -C test.tmp 
00000000  04 00 00 00 60 01 00 00  ff ff ff ff ff ff ff ff  |....`...........|
00000010  ff ff ff ff 16 00 00 00  00 00 00 00 62 17 01 00  |............b...|
00000020  00 00 00 00 03 00 75 00  00 00 00 00 01 00 ff ff  |......u.........|
00000030  52 00 5a 00 00 00 83 00  00 00 7b 04 00 02 04 00  |R.Z.......{.....|
00000040  00 00 08 00 00 00 54 0a  04 00 00 00 08 00 00 00  |......T.........|
00000050  0c 0a 00 00 00 00 00 00  00 00 ff ff ff ff ff ff  |................|
00000060  ff ff 00 13 00 9a 02 00  00 01 00 00 00 00 00 5c  |...............\|
00000070  56 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |V...............|
00000080  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00001ff0  00 00 5a 00 62 00 52 00  00 00 00 00 00 00 00 00  |..Z.b.R.........|
00002000

偏移量98开始 19个字节


13 00 9a 02 00  00 01 00 00 00 00 00 5c 56 00 00 00 00 00

9a 02 00 00 KEY值 666
01 00 00 00 逻辑ROWID 1
56 5c TRXID 22108 用于MVCC可见性处理
二级索引中存储了自身的KEY值和表的逻辑ROWID,用于定位实际的数据行,这样就可以对应到表数据行的CLU_ROWID来找到对应行物理位置了

多级索引情况

当我们数据较多,索引分裂出现多个节点的时候,情况会变得稍微有些复杂,这里我们不必再考虑数据的问题,仅测试寻址的变化

drop table test;
create table test(id int,name varchar(100),primary key(id))

begin
for i in 100..1000
loop
insert into test values(i,'test');
end loop;
end;
select checkpoint(100)

此时我们来观察索引的情况

SQL> select OBJECT_ID,INDEX_NAME,INDEX_TYPE,OBJECT_TYPE,INDEX_TYPE,UNIQUENESS
 from dba_indexes a,dba_objects b 
 where TABLE_NAME='TEST' and a.INDEX_NAME=B.OBJECT_NAME;

行号     OBJECT_ID INDEX_NAME    INDEX_TYPE OBJECT_TYPE INDEX_TYPE UNIQUENESS
---------- --------- ------------- ---------- ----------- ---------- ----------
1          33555845  INDEX33555845 NORMAL     INDEX       NORMAL     UNIQUE
2          33555844  INDEX33555844 CLUSTER    INDEX       CLUSTER    NONUNIQUE

已用时间: 235.830(毫秒). 执行号:76706.

此时索引将会出现多个页

SQL> select * from v$segmentinfo where index_id=33555844;

行号     INDEX_ID    SEG_ID      LOGIC_PAGE_NO PHY_PAGE_NO PHY_FIRST_PAGE_IN_EXTENT FIL_ID      USE_BYTES            FREE_BYTES          
---------- ----------- ----------- ------------- ----------- ------------------------ ----------- -------------------- --------------------
1          33555844    2922        0             7232        7232                     0           8162                 30
2          33555844    2922        1             7265        7264                     0           8162                 30
3          33555844    2922        2             7266        7264                     0           8162                 30
4          33555844    2922        3             7267        7264                     0           5687                 2505

已用时间: 0.968(毫秒). 执行号:76707.

而且有趣的是第一个页与后续是不连续的,分别观察一下这几个页的内容

SQL> DECLARE
HEAD DBMS_PAGE.DPH_T;
INFO dbms_page.REC_ARR_T;
BASN int = 7232;
TBSN int = 4;
FILN int = 0;

BEGIN
    for i in 0..10 loop
        begin
        DBMS_PAGE.DATA_PAGE_HEAD_LOAD(TBSN,FILN,BASN,HEAD);
        if(HEAD.N_REC)>0 then
           a[i] = BASN;
           print 'PAGE_NO:'||BASN||' RECORD NUMBER:'||HEAD.N_REC;
           INFO = NEW dbms_page.REC_T[HEAD.N_REC];
           FOR J IN 1..HEAD.N_REC LOOP
               DBMS_PAGE.DATA_PAGE_REC_BY_SLOT_NO_LOAD(TBSN ,FILN,BASN,J,INFO[J]);
           END LOOP;
           SELECT * FROM ARRAY INFO;
        end if;
        exception
           when OTHERS then NULL;
        end;
   BASN = BASN +i;
   end loop;
END;  
/

行号     SLOT_NO     OFFSET      LEN         IS_DEL      TRX_ID               CLU_ROWID            ROLL_ADDR_FILE ROLL_ADDR_PAGE ROLL_ADDR_OFF
---------- ----------- ----------- ----------- ----------- -------------------- -------------------- -------------- -------------- -------------
1          1           7631        15          0           245                  NULL                 NULL           NULL           NULL
2          2           7600        15          0           489                  NULL                 NULL           NULL           NULL
3          3           7569        15          0           733                  NULL                 NULL           NULL           NULL

已用时间: 38.674(毫秒). 执行号:76708.

这个页里CLU_ROWID为NULL了,只有3行内容,但是TRX_ID变了,同一个TRX操作确产生不同TRX_ID,并且SLOT_NO按OFFSET逆序进行记录,先来看看后面3个页
首先看看7265

SQL> DECLARE
HEAD DBMS_PAGE.DPH_T;
INFO dbms_page.REC_ARR_T;
BASN int = 7265;
TBSN int = 4;
FILN int = 0;

BEGIN
    for i in 0..1 loop
        begin
        DBMS_PAGE.DATA_PAGE_HEAD_LOAD(TBSN,FILN,BASN,HEAD);
        if(HEAD.N_REC)>0 then
           a[i] = BASN;
                      print 'PAGE_NO:'||BASN||' RECORD NUMBER:'||HEAD.N_REC;
           INFO = NEW dbms_page.REC_T[HEAD.N_REC];
           FOR J IN 1..HEAD.N_REC LOOP
               DBMS_PAGE.DATA_PAGE_REC_BY_SLOT_NO_LOAD(TBSN   ,FILN,BASN,J,INFO[J]);
           END LOOP;
           SELECT * FROM ARRAY INFO;
        end if;
        exception
           when OTHERS then NULL;
        end;
   BASN = BASN +i;
   end loop;
END; 
/

行号     SLOT_NO     OFFSET      LEN         IS_DEL      TRX_ID               CLU_ROWID            ROLL_ADDR_FILE ROLL_ADDR_PAGE ROLL_ADDR_OFF
---------- ----------- ----------- ----------- ----------- -------------------- -------------------- -------------- -------------- -------------
1          1           98          31          0           423172               245                  NULL           NULL           NULL
2          2           129         31          0           423172               246                  NULL           NULL           NULL
3          3           160         31          0           423172               247                  NULL           NULL           NULL
......

行号     SLOT_NO     OFFSET      LEN         IS_DEL      TRX_ID               CLU_ROWID            ROLL_ADDR_FILE ROLL_ADDR_PAGE ROLL_ADDR_OFF
---------- ----------- ----------- ----------- ----------- -------------------- -------------------- -------------- -------------- -------------
232        232         7259        31          0           423172               476                  NULL           NULL           NULL
233        233         7290        31          0           423172               477                  NULL           NULL           NULL
234        234         7321        31          0           423172               478                  NULL           NULL           NULL
235        235         7352        31          0           423172               479                  NULL           NULL           NULL
236        236         7383        31          0           423172               480                  NULL           NULL           NULL
237        237         7414        31          0           423172               481                  NULL           NULL           NULL
238        238         7445        31          0           423172               482                  NULL           NULL           NULL
239        239         7476        31          0           423172               483                  NULL           NULL           NULL
240        240         7507        31          0           423172               484                  NULL           NULL           NULL
241        241         7538        31          0           423172               485                  NULL           NULL           NULL
242        242         7569        31          0           423172               486                  NULL           NULL           NULL

行号     SLOT_NO     OFFSET      LEN         IS_DEL      TRX_ID               CLU_ROWID            ROLL_ADDR_FILE ROLL_ADDR_PAGE ROLL_ADDR_OFF
---------- ----------- ----------- ----------- ----------- -------------------- -------------------- -------------- -------------- -------------
243        243         7600        31          0           423172               487                  NULL           NULL           NULL
244        244         7631        31          0           423172               488                  NULL           NULL           NULL

244 rows got

已用时间: 1.896(毫秒). 执行号:168200.

再看看7266

SQL> DECLARE
HEAD DBMS_PAGE.DPH_T;
INFO dbms_page.REC_ARR_T;
BASN int = 7266;
TBSN int = 4;
FILN int = 0;

BEGIN
    for i in 0..1 loop
        begin
        DBMS_PAGE.DATA_PAGE_HEAD_LOAD(TBSN,FILN,BASN,HEAD);
        if(HEAD.N_REC)>0 then
           a[i] = BASN;
                      print 'PAGE_NO:'||BASN||' RECORD NUMBER:'||HEAD.N_REC;
           INFO = NEW dbms_page.REC_T[HEAD.N_REC];
           FOR J IN 1..HEAD.N_REC LOOP
               DBMS_PAGE.DATA_PAGE_REC_BY_SLOT_NO_LOAD(TBSN   ,FILN,BASN,J,INFO[J]);
           END LOOP;
           SELECT * FROM ARRAY INFO;
        end if;
        exception
           when OTHERS then NULL;
        end;
   BASN = BASN +i;
   end loop;
END; 
/
......
行号     SLOT_NO     OFFSET      LEN         IS_DEL      TRX_ID               CLU_ROWID            ROLL_ADDR_FILE ROLL_ADDR_PAGE ROLL_ADDR_OFF
---------- ----------- ----------- ----------- ----------- -------------------- -------------------- -------------- -------------- -------------
232        232         7259        31          0           423172               720                  NULL           NULL           NULL
233        233         7290        31          0           423172               721                  NULL           NULL           NULL
234        234         7321        31          0           423172               722                  NULL           NULL           NULL
235        235         7352        31          0           423172               723                  NULL           NULL           NULL
236        236         7383        31          0           423172               724                  NULL           NULL           NULL
237        237         7414        31          0           423172               725                  NULL           NULL           NULL
238        238         7445        31          0           423172               726                  NULL           NULL           NULL
239        239         7476        31          0           423172               727                  NULL           NULL           NULL
240        240         7507        31          0           423172               728                  NULL           NULL           NULL
241        241         7538        31          0           423172               729                  NULL           NULL           NULL
242        242         7569        31          0           423172               730                  NULL           NULL           NULL

行号     SLOT_NO     OFFSET      LEN         IS_DEL      TRX_ID               CLU_ROWID            ROLL_ADDR_FILE ROLL_ADDR_PAGE ROLL_ADDR_OFF
---------- ----------- ----------- ----------- ----------- -------------------- -------------------- -------------- -------------- -------------
243        243         7600        31          0           423172               731                  NULL           NULL           NULL
244        244         7631        31          0           423172               732                  NULL           NULL           NULL

244 rows got

已用时间: 1.813(毫秒). 执行号:168201.

最后是7267

SQL> DECLARE
HEAD DBMS_PAGE.DPH_T;
INFO dbms_page.REC_ARR_T;
BASN int = 7266;
TBSN int = 4;
FILN int = 0;

BEGIN
    for i in 0..1 loop
        begin
        DBMS_PAGE.DATA_PAGE_HEAD_LOAD(TBSN,FILN,BASN,HEAD);
        if(HEAD.N_REC)>0 then
           a[i] = BASN;
                      print 'PAGE_NO:'||BASN||' RECORD NUMBER:'||HEAD.N_REC;
           INFO = NEW dbms_page.REC_T[HEAD.N_REC];
           FOR J IN 1..HEAD.N_REC LOOP
               DBMS_PAGE.DATA_PAGE_REC_BY_SLOT_NO_LOAD(TBSN   ,FILN,BASN,J,INFO[J]);
           END LOOP;
           SELECT * FROM ARRAY INFO;
        end if;
        exception
           when OTHERS then NULL;
        end;
   BASN = BASN +i;
   end loop;
END; 
/
......
行号     SLOT_NO     OFFSET      LEN         IS_DEL      TRX_ID               CLU_ROWID            ROLL_ADDR_FILE ROLL_ADDR_PAGE ROLL_ADDR_OFF
---------- ----------- ----------- ----------- ----------- -------------------- -------------------- -------------- -------------- -------------
144        144         4531        31          0           423172               876                  NULL           NULL           NULL
145        145         4562        31          0           423172               877                  NULL           NULL           NULL
146        146         4593        31          0           423172               878                  NULL           NULL           NULL
147        147         4624        31          0           423172               879                  NULL           NULL           NULL
148        148         4655        31          0           423172               880                  NULL           NULL           NULL
149        149         4686        31          0           423172               881                  NULL           NULL           NULL
150        150         4717        31          0           423172               882                  NULL           NULL           NULL
151        151         4748        31          0           423172               883                  NULL           NULL           NULL
152        152         4779        31          0           423172               884                  NULL           NULL           NULL
153        153         4810        31          0           423172               885                  NULL           NULL           NULL
154        154         4841        31          0           423172               886                  NULL           NULL           NULL

行号     SLOT_NO     OFFSET      LEN         IS_DEL      TRX_ID               CLU_ROWID            ROLL_ADDR_FILE ROLL_ADDR_PAGE ROLL_ADDR_OFF
---------- ----------- ----------- ----------- ----------- -------------------- -------------------- -------------- -------------- -------------
155        155         4872        31          0           423172               887                  NULL           NULL           NULL
156        156         4903        31          0           423172               888                  NULL           NULL           NULL
157        157         4934        31          0           423172               889                  NULL           NULL           NULL
158        158         4965        31          0           423172               890                  NULL           NULL           NULL
159        159         4996        31          0           423172               891                  NULL           NULL           NULL
160        160         5027        31          0           423172               892                  NULL           NULL           NULL
161        161         5058        31          0           423172               893                  NULL           NULL           NULL
162        162         5089        31          0           423172               894                  NULL           NULL           NULL
163        163         5120        31          0           423172               895                  NULL           NULL           NULL
164        164         5151        31          0           423172               896                  NULL           NULL           NULL
165        165         5182        31          0           423172               897                  NULL           NULL           NULL

行号     SLOT_NO     OFFSET      LEN         IS_DEL      TRX_ID               CLU_ROWID            ROLL_ADDR_FILE ROLL_ADDR_PAGE ROLL_ADDR_OFF
---------- ----------- ----------- ----------- ----------- -------------------- -------------------- -------------- -------------- -------------
166        166         5213        31          0           423172               898                  NULL           NULL           NULL
167        167         5244        31          0           423172               899                  NULL           NULL           NULL
168        168         5275        31          0           423172               900                  NULL           NULL           NULL
169        169         5306        31          0           423172               901                  NULL           NULL           NULL

169 rows got

已用时间: 2.561(毫秒). 执行号:168202.

后面的3个页中我们找到了CLU_ROWID,这样情况就和未分裂之前相同了,那么第一个索引页末尾那3行是什么呢,实际上那个TRX_ID记录的是该页中ROWID的下限值,具体分析过程比较繁琐,无非是一些解物理存储进行比对,在此不再赘述。

再思考一下

回到此前的问题,ROWID小于245的部分又去哪了呢?
换个思路,MySQL底层存储思路也是通过记录下限值来划分边界,这就意味着最小值应该是-1,这是不是意味着我们看到的记录的第一个实际数据页之前就是记录所有低于下限值的数据页呢

[root@dm8host7 demo]# dd if=/home/DM8/data/DAMENG/MAIN.DBF of=/tmp/test.dbf bs=8192 skip=7264 count=1

[root@dm8host7 demo]# hexdump -C /tmp/test.dbf |more
00000000  04 00 00 00 60 1c 00 00  ff ff ff ff ff ff 00 00  |....`...........|
00000010  61 1c 00 00 14 00 00 00  00 00 00 00 fa 8f ab 00  |a...............|
00000020  00 00 00 00 f6 00 ee 1d  00 00 00 00 f4 00 ff ff  |................|
00000030  52 00 5a 00 00 00 e2 1f  00 00 84 05 00 02 00 00  |R.Z.............|
00000040  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000050  00 00 00 00 00 00 00 00  00 00 ff ff ff ff ff ff  |................|
00000060  ff ff 00 1f 00 64 00 00  00 84 74 65 73 74 01 00  |.....d....test..|
00000070  00 00 00 00 ff ff ff ff  7f ff ff 04 75 06 00 00  |............u...|
00000080  00 00 1f 00 65 00 00 00  84 74 65 73 74 02 00 00  |....e....test...|
00000090  00 00 00 ff ff ff ff 7f  ff ff 04 75 06 00 00 00  |...........u....|
000000a0  00 1f 00 66 00 00 00 84  74 65 73 74 03 00 00 00  |...f....test....|
000000b0  00 00 ff ff ff ff 7f ff  ff 04 75 06 00 00 00 00  |..........u.....|
000000c0  1f 00 67 00 00 00 84 74  65 73 74 04 00 00 00 00  |..g....test.....|
000000d0  00 ff ff ff ff 7f ff ff  04 75 06 00 00 00 00 1f  |.........u......|

页头的部分是固定的98,那么来看看这之后放了些啥

                00 1f 00 64 00 00  00 84 74 65 73 74 01 00  |.....d....test..|
00000070  00 00 00 00 ff ff ff ff  7f ff ff 04 75 06 00 00  |............u...|
00000080  00 00 1f 00 65 00 00 00  84 74 65 73 74 02 00 00  |....e....test...|
00000090  00 00 00 ff ff ff ff 7f  ff ff 04 75 06 00 00 00  |...........u....|
000000a0  00 1f 00 66 00 00 00 84  74 65 73 74 03 00 00 00  |...f....test....|
000000b0  00 00 ff ff ff ff 7f ff  ff 04 75 06 00 00 00 00  |..........u.....|
000000c0  1f 00 67 00 00 00 84 74  65 73 74 04 00 00 00 00  |..g....test.....|
000000d0  00 ff ff ff ff 7f ff ff  04 75 06 00 00 00 00 1f  |.........u......|

由于数据较多,我这里只提取前几行,后面都是类似的内容。
是的,这便是从ROWID 1开始的行数据,为了保险起见我们再验证一下末尾最后一行数据记录的是啥

00001db0  00 1f 00 56 01 00 00 84  74 65 73 74 f3 00 00 00  |...V....test....|
00001dc0  00 00 ff ff ff ff 7f ff  ff 04 75 06 00 00 00 00  |..........u.....|
00001dd0  1f 00 57 01 00 00 84 74  65 73 74 f4 00 00 00 00  |..W....test.....|
00001de0  00 ff ff ff ff 7f ff ff  04 75 06

正好这里的最后一行ROWID是244,这就完美对应上了,同时我们也可以从头部信息得到反向佐证

DECLARE
HEAD DBMS_PAGE.DPH_T;
INFO dbms_page.REC_ARR_T;
BASN int = 7264;
TBSN int = 4;
FILN int = 0;

BEGIN
    for i in 0..1 loop
        begin
        DBMS_PAGE.DATA_PAGE_HEAD_LOAD(TBSN,FILN,BASN,HEAD);
        if(HEAD.N_REC)>0 then
           a[i] = BASN;
                      print 'PAGE_NO:'||BASN||' RECORD NUMBER:'||HEAD.N_REC;
           INFO = NEW dbms_page.REC_T[HEAD.N_REC];
           FOR J IN 1..HEAD.N_REC LOOP
               DBMS_PAGE.DATA_PAGE_REC_BY_SLOT_NO_LOAD(TBSN   ,FILN,BASN,J,INFO[J]);
           END LOOP;
           SELECT * FROM ARRAY INFO;
        end if;
        exception
           when OTHERS then NULL;
        end;
   BASN = BASN +i;
   end loop;
END;
/
......

行号     SLOT_NO     OFFSET      LEN         IS_DEL      TRX_ID               CLU_ROWID            ROLL_ADDR_FILE ROLL_ADDR_PAGE ROLL_ADDR_OFF
---------- ----------- ----------- ----------- ----------- -------------------- -------------------- -------------- -------------- -------------
232        232         7259        31          0           423172               232                  NULL           NULL           NULL
233        233         7290        31          0           423172               233                  NULL           NULL           NULL
234        234         7321        31          0           423172               234                  NULL           NULL           NULL
235        235         7352        31          0           423172               235                  NULL           NULL           NULL
236        236         7383        31          0           423172               236                  NULL           NULL           NULL
237        237         7414        31          0           423172               237                  NULL           NULL           NULL
238        238         7445        31          0           423172               238                  NULL           NULL           NULL
239        239         7476        31          0           423172               239                  NULL           NULL           NULL
240        240         7507        31          0           423172               240                  NULL           NULL           NULL
241        241         7538        31          0           423172               241                  NULL           NULL           NULL
242        242         7569        31          0           423172               242                  NULL           NULL           NULL

行号     SLOT_NO     OFFSET      LEN         IS_DEL      TRX_ID               CLU_ROWID            ROLL_ADDR_FILE ROLL_ADDR_PAGE ROLL_ADDR_OFF
---------- ----------- ----------- ----------- ----------- -------------------- -------------------- -------------- -------------- -------------
243        243         7600        31          0           423172               243                  NULL           NULL           NULL
244        244         7631        31          0           423172               244                  NULL           NULL           NULL

244 rows got

已用时间: 2.539(毫秒). 执行号:181701.

聊聊数据顺序维护

这里我建立一个按CLUSTER PK组织的表,并刻意插入反序的int和varchar数值,此时磁盘数据如下

00000000  04 00 00 00 10 1d 00 00  ff ff ff ff ff ff ff ff  |................|
00000010  ff ff ff ff 14 00 00 00  00 00 00 00 f1 39 ac 00  |.............9..|
00000020  00 00 00 00 07 00 ee 00  00 00 00 00 05 00 ff ff  |................|
00000030  52 00 5a 00 00 00 04 01  00 00 86 05 00 02 04 00  |R.Z.............|
00000040  00 00 01 08 00 00 34 09  04 00 00 00 01 08 00 00  |......4.........|
00000050  ec 08 00 00 00 00 00 00  00 00 ff ff ff ff ff ff  |................|
00000060  ff ff 00 1c 00 0a 00 00  00 81 7a 01 00 00 00 00  |..........z.....|
00000070  00 ff ff ff ff 7f ff ff  90 d2 06 00 00 00 00 1c  |................|
00000080  00 09 00 00 00 81 79 02  00 00 00 00 00 ff ff ff  |......y.........|
00000090  ff 7f ff ff 92 d2 06 00  00 00 00 1c 00 08 00 00  |................|
000000a0  00 81 78 03 00 00 00 00  00 ff ff ff ff 7f ff ff  |..x.............|
000000b0  93 d2 06 00 00 00 00 1c  00 07 00 00 00 81 72 04  |..............r.|
000000c0  00 00 00 00 00 ff ff ff  ff 7f ff ff 94 d2 06 00  |................|
000000d0  00 00 00 1c 00 06 00 00  00 81 61 05 00 00 00 00  |..........a.....|
000000e0  00 ff ff ff ff 7f ff ff  95 d2 06 00 00 00 00 00  |................|
000000f0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00001fe0  00 00 00 00 00 00 00 00  00 00 5a 00 62 00 7e 00  |..........Z.b.~.|
00001ff0  9a 00 b6 00 d2 00 52 00  00 00 00 00 00 00 00 00  |......R.........|

二级索引数据如下

[root@dm8host7 ~]# hexdump -C /tmp/test1_idx.dbf 
00000000  04 00 00 00 20 1d 00 00  ff ff ff ff ff ff ff ff  |.... ...........|
00000010  ff ff ff ff 16 00 00 00  00 00 00 00 f2 39 ac 00  |.............9..|
00000020  00 00 00 00 07 00 cb 00  00 00 00 00 05 00 ff ff  |................|
00000030  52 00 5a 00 00 00 e1 00  00 00 88 05 00 02 04 00  |R.Z.............|
00000040  00 00 01 08 00 00 c4 09  04 00 00 00 01 08 00 00  |................|
00000050  7c 09 00 00 00 00 00 00  00 00 ff ff ff ff ff ff  ||...............|
00000060  ff ff 00 15 00 0a 00 00  00 81 7a 01 00 00 00 00  |..........z.....|
00000070  00 90 d2 06 00 00 00 00  15 00 09 00 00 00 81 79  |...............y|
00000080  02 00 00 00 00 00 92 d2  06 00 00 00 00 15 00 08  |................|
00000090  00 00 00 81 78 03 00 00  00 00 00 93 d2 06 00 00  |....x...........|
000000a0  00 00 15 00 07 00 00 00  81 72 04 00 00 00 00 00  |.........r......|
000000b0  94 d2 06 00 00 00 00 15  00 06 00 00 00 81 61 05  |..............a.|
000000c0  00 00 00 00 00 95 d2 06  00 00 00 00 00 00 00 00  |................|
000000d0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00001fe0  00 00 00 00 00 00 00 00  00 00 5a 00 62 00 77 00  |..........Z.b.w.|
00001ff0  8c 00 a1 00 b6 00 52 00  00 00 00 00 00 00 00 00  |......R.........|
00002000

相关数据看起来和我插入顺序一模一样,也并没有针对我要的顺序排序,这样似乎不太合理,那么继续看数据页和索引页的页头
数据页

SQL>  DECLARE
HEAD DBMS_PAGE.DPH_T;
INFO dbms_page.REC_ARR_T;
BASN int = 7440;
TBSN int = 4;
FILN int = 0;

BEGIN
    for i in 0..1 loop
        begin
        DBMS_PAGE.DATA_PAGE_HEAD_LOAD(TBSN,FILN,BASN,HEAD);
        if(HEAD.N_REC)>0 then
           print 'PA2   3   4   5   6   7   8   9   10  11  12  13  GE_NO:'||BASN||' RECORD NUMBER:'||HEAD.N_REC;
           INFO = NEW dbms_page.REC_T[HEAD.N_REC];
           FOR J IN 1..HEAD.N_REC LOOP
               DBMS_PAGE.DATA_PAGE_REC_BY_SLOT_NO_LOAD(TBSN  ,FILN,BASN,J,INFO[J]);
           END LOOP;
           SELE14  15  16  17  18  CT * FROM ARRAY INFO;
        end if;
        exception
           when OTHERS then NULL;
        end;
   BASN = BASN +i;
   end loop;
END;19  20  21  22  23  24  25  
26  /

行号     SLOT_NO     OFFSET      LEN         IS_DEL      TRX_ID               CLU_ROWID            ROLL_ADDR_FILE ROLL_ADDR_PAGE ROLL_ADDR_OFF
---------- ----------- ----------- ----------- ----------- -------------------- -------------------- -------------- -------------- -------------
1          1           210         28          0           447125               5                    NULL           NULL           NULL
2          2           182         28          0           447124               4                    NULL           NULL           NULL
3          3           154         28          0           447123               3                    NULL           NULL           NULL
4          4           126         28          0           447122               2                    NULL           NULL           NULL
5          5           98          28          0           447120               1                    NULL           NULL           NULL

已用时间: 18.704(毫秒). 执行号:198400.

索引页

SQL> DECLARE
HEAD DBMS_PAGE.DPH_T;
INFO dbms_page.REC_ARR_T;
BASN int = 7456;
TBSN int = 4;
FILN int = 0;

BEGIN
    for i in 0..1 loop
        begin
        DBMS_PAGE.DATA_PAGE_HEAD_LOAD(TBSN,FILN,BASN,HEAD);
        if(HEAD.N_REC)>0 then
           a[i] = BASN;
           print 'PAGE_NO:'||BASN||' RECORD NUMBER:'||HEAD.N_REC;
           INFO = NEW dbms_page.REC_T[HEAD.N_REC];
           FOR J IN 1..HEAD.N_REC LOOP
               DBMS_PAGE.DATA_PAGE_REC_BY_SLOT_NO_LOAD(TBSN  ,FILN,BASN,J,INFO[J]);
           END LOOP;
           SELECT * FROM ARRAY INFO;
        end if;
        exception
           when OTHERS then NULL;
        end;
   BASN = BASN +i;
   end loop;
END;
/

行号     SLOT_NO     OFFSET      LEN         IS_DEL      TRX_ID              
---------- ----------- ----------- ----------- ----------- --------------------
           CLU_ROWID            ROLL_ADDR_FILE ROLL_ADDR_PAGE ROLL_ADDR_OFF
           -------------------- -------------- -------------- -------------
1          1           182         21          0           447125
           NULL                 97             5              0

2          2           161         21          0           447124
           NULL                 114            4              0

3          3           140         21          0           447123
           NULL                 120            3              0


行号     SLOT_NO     OFFSET      LEN         IS_DEL      TRX_ID              
---------- ----------- ----------- ----------- ----------- --------------------
           CLU_ROWID            ROLL_ADDR_FILE ROLL_ADDR_PAGE ROLL_ADDR_OFF
           -------------------- -------------- -------------- -------------
4          4           119         21          0           447122
           NULL                 121            2              0

5          5           98          21          0           447120
           NULL                 122            1              0


已用时间: 1.258(毫秒). 执行号:195700.

实际上这里通过SLOT_NO正序和磁盘尾部OFFSET逆序组合来满足了我们索引排序的顺序,而避免了在存储时重新排序数据的操作,这样设计在IO时应当能够有效消除额外排序动作的开销


总结

到此就完成了一个最简单的寻址测试,实际使用场景还需要考量更多的机制和问题,欢迎了解的同学共同分享。

举报

相关推荐

0 条评论