Oracle Database 中 关于 null值的存储

这里主要验证了number 和 varchar2 两种数据类型null值的存储

先来介绍一下row piece的结构

引用官方文档的一张结构图



通常情况下,不包括(cluster table 和 chain row)一个rowpiece 包括row header 和 column data

关于其他情况,会在以后的研究中陆续放出。

BBED> dump /v
File: /u01/apps/oracle/oradata/david/users01.dbf(4)
Block: 531 Offsets: 8173to 8191Dba:0x01000213
-------------------------------------------------------
3c020302 c1020353 59530444 55414c01 l<...á..SYS.DUAL.
06fbd4 l .ûÔ
<16 bytes per line>

例如:一个rowpiece的前3个字节 3c0203它表示

1个字节的flag
1个字节的lb(itl slot)
1个字节的columncount

如例中
3c=flag=00111100=--HDFL--=header+delete+first+last
02=lb itl slot 0x02
03=column count


列值信息包括:
列的长度,列的value
例如02c102
表示占用2个byte
c102 表示的是具体的值

dump 的信息 可以使用 UTL_RAW.CAST_TO_xxxx 来翻译(感谢itpubiori809的指导)




下面开始验证

首先环境为11.1.0.6 linux x64

dex@FAKE> desc ts
 Name                                                              Null?    Type
 ----------------------------------------------------------------- -------- --------------------------------------------
 ID                                                                         NUMBER
 NAME                                                                       VARCHAR2(20)
 COUNT                                                                      NUMBER


dex@FAKE> select t.*,
  2         dbms_rowid.rowid_relative_fno(t.rowid) as "FNO#",
  3         dbms_rowid.rowid_block_number(t.rowid) as "BLK#",
  4         dbms_rowid.rowid_row_number(t.rowid) as "ROW#"
  5    from dex.ts t
  6  ;


        ID NAME                      COUNT       FNO#       BLK#       ROW#
---------- -------------------- ---------- ---------- ---------- ----------
         1 dd                                       4         31          0
         2                               2          4         31          1
           2                             3          4         31          2
         4                                          4         31          3

建表语句:dex@FAKE> create table ts ( id number , name varchar2(20) , count number ) ;
因为表中没有使用long 类型的column,所以表中列的顺序和建表中的列的声明顺序相同。
BBED> set dba 4,31
DBA 0x0100001f (16777247 4,31)
BBED> map
File: /u01/apps/oracle/oradata/fake/users01.dbf (4)
Block: 31 Dba:0x0100001f
------------------------------------------------------------
KTB Data Block (Table/Cluster)


struct kcbh, 20 bytes @0


struct ktbbh, 72 bytes @20


struct kdbh, 14 bytes @100


struct kdbt[1], 4 bytes @114


sb2 kdbr[3] @118


ub1 freespace[8036] @124


ub1 rowdata[28] @8160


ub4 tailchk @8188


首先看来看第一行id=1 的row#=0 的 rowpiece
BBED> p *kdbr[0]
rowdata[19]
-----------

ub1 rowdata[19]

BBED> set offset 8179
OFFSET 8179
BBED> dump /v count 128
File: /u01/apps/oracle/oradata/fake/users01.dbf (4)
Block: 31 Offsets: 8179 to 8191 Dba:0x0100001f
-------------------------------------------------------
2c010202 c1020264 64010669 9f l ,...Á..dd..i.


<16 bytes per line>

2c010202 c1020264 64 这些是rowpiece
第一行对应表中的值为
dex@FAKE> select * from ts where id=1 ;


ID NAME COUNT
---------- -------------------- ----------
1 dd

可以看到id=1 的row#=0 ,这里的最后一列COUNT(number类型)值为null ,没有存储在block中,并且count number 标识为 拥有2列


我们再来看第二行 id=2 row#=1 的row piece

BBED> p *kdbr[1]
rowdata[9]
----------
ub1 rowdata[9] @8169 0x2c
BBED> dump /v offset 8169 count 128
File: /u01/apps/oracle/oradata/fake/users01.dbf (4)
Block: 31 Offsets: 8169 to 8191 Dba:0x0100001f
-------------------------------------------------------
2c010302 c103ff02 c1032c01 0202c102 l ,...Á...Á.,...Á.
02646401 06699f l .dd..i.


<16 bytes per line>
2c010302 c103ff02 c103 这些为第二行的rowpiece


对应表中的值为
ID NAME COUNT
---------- -------------------- ----------
2 2

第二列name(varchar2类型) 为null
这里是怎样存储的呢?因为不是row piece 中的最后一列,可以看到是使用了ff来表示长度为0


再来看第三行 id=null row#=2 的row piece
BBED> p *kdbr[2]
rowdata[0]
----------
ub1 rowdata[0] @8160 0x2c

BBED> dump /v offset 8160 count 128
File: /u01/apps/oracle/oradata/fake/users01.dbf (4)
Block: 31 Offsets: 8160 to 8191 Dba:0x0100001f
-------------------------------------------------------
2c0103ff 013202c1 042c0103 02c103ff l ,....2.Á.,...Á..
02c1032c 010202c1 02026464 0106699f l .Á.,...Á..dd..i.


<16 bytes per line>

rowpiece为 2c0103ff 013202c1 04


对应表中的值
dex@FAKE> select * from ts where id is null ;


ID NAME COUNT
---------- -------------------- ----------
2 3

可以看到第一列id(number类型) 为null
也是使用ff来表示的。


最后看一下第四行 id=4 row#=3 的row piece


BBED> dump /v offset 8154 count 128
File: /u01/apps/oracle/oradata/fake/users01.dbf (4)
Block: 31 Offsets: 8154 to 8191 Dba:0x0100001f
-------------------------------------------------------
2c020102 c1052c01 03ff0132 02c1042c l ,...Á.,....2.Á.,
010302c1 03ff02c1 032c0102 02c10202 l ...Á...Á.,...Á..
64640206 b2a1 l dd..²¡


<16 bytes per line>


rowpiece 为 2c020102 c105
对应表中的值为
dex@FAKE> select * from ts where id=4 ;


ID NAME COUNT
---------- -------------------- ----------
4


可以看到row piece 中表示row piece 中只包含1列
因为后两列 name 与 count 的值都为空,所以也没有使用ff来表示。











想想也是蛮有道理的,如果不使用ff来表示,没有办法保证列的顺序。

而当后面的列的值都为null的时候,自然可以省下1个字节的ff。

至此验证结束





验证结束
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值