Oracle基础数据的存储格式

本文深入探讨Oracle数据库中Char, Varchar2, Number, Date等基础数据类型的存储方式。Char是定长,Varchar2是不定长,Number存储采用科学计数法,Date则是定长7字节。通过实验展示了不同类型数据在Oracle内部的存储格式和算法。" 24055607,1457724,使用二叉树先序遍历求解集合幂集,"['数据结构', '算法', '二叉树遍历']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文对日常开发过程中常遇到的几种基础数据类型在oracle中的存储做了一个简单的回顾。主要涉及char,varchar2,number,date,timestamp,raw等几种数据类型。

 

1  Char:定长,依赖于定义的数据长度。

 

2  Varchar2:不定长,依赖于实际存储的数据长度。

通过如下实验来验证一把:

SQL>CREATETABLE t_test(aCHAR(10), bVARCHAR2(10));

SQL>INSERTINTO t_test(a,b)VALUES('abc','abc');

SQL>COMMIT;

SQL>SELECTDUMP(t.a,16) DA,DUMP(t.B,16) DBFROM t_test t;

             DA                                      DB

Typ=96 Len=10: 61,62,63,20,20,20,20,20,20,20          Typ=1 Len=3: 61,62,63

上面的实验可以看到,数据的存储还是以ASCII码的格式存储的。

 

3  Number:不定长,依赖于实际存储的数据。

Number类型的数据比char和varchar2要稍微复杂一点,oracle在存储number类型的数据时,为了尽量少的占用存储空间,特地的使用了算法来描述数据的存储过程。总体来说,oracle是按照科学计数法来表示一个数据的,oracle采用了变长的1到22字节数据来存储。其中第1位是一个标志位,该位标示了数字的符号位及表示该数字的指数的符号位。

可以看一些number类型数据存储的例子:

SQL> SELECT DUMP(123456789,16) FROM dual;

DUMP(123456789,16)

-----------------------------

Typ=2 Len=6: c5,2,18,2e,44,5a

SQL> SELECT DUMP(12345678,16) FROM dual;

DUMP(12345678,16)

--------------------------

Typ=2 Len=5: c4,d,23,39,4f

SQL> SELECT DUMP(1234567,16) FROM dual;

DUMP(1234567,16)

--------------------------

Typ=2 Len=5: c4,2,18,2e,44

SQL> SELECT DUMP(123456,16) FROM dual;

DUMP(123456,16)

-----------------------

Typ=2 Len=4: c3,d,23,39

SQL> SELECT DUMP(12345,16) FROM dual;

DUMP(12345,16)

-----------------------

Typ=2 Len=4: c3,2,18,2e

SQL> SELECT DUMP(1234,16) FROM dual;

DUMP(1234,16)

--------------------

Typ=2 Len=3: c2,d,23

SQL> SELECT DUMP(123,16) FROM dual;

DUMP(123,16)

--------------------

Typ=2 Len=3: c2,2,18

SQL> SELECT DUMP(12,16) FROM dual;

DUMP(12,16)

-----------------

Typ=2 Len=2: c1,d

SQL> SELECT DUMP(1,16) FROM dual;

DUMP(1,16)

-----------------

Typ=2 Len=2: c1,2

SQL> SELECT DUMP(0,16) FROM dual;

DUMP(0,16)

---------------

Typ=2 Len=1: 80

SQL> SELECT DUMP(-1,16) FROM dual;

DUMP(-1,16)

---------------------

Typ=2 Len=3: 3e,64,66

SQL> SELECT DUMP(-12,16) FROM dual;

DUMP(-12,16)

---------------------

Typ=2 Len=3: 3e,59,66

SQL> SELECT DUMP(-123,16) FROM dual;

DUMP(-123,16)

------------------------

Typ=2 Len=4: 3d,64,4e,66

SQL> SELECT DUMP(-1234,16) FROM dual;

DUMP(-1234,16)

------------------------

Typ=2 Len=4: 3d,59,43,66

SQL> SELECT DUMP(-12345,16) FROM dual;

DUMP(-12345,16)

---------------------------

Typ=2 Len=5: 3c,64,4e,38,66

SQL> SELECT DUMP(-123456,16) FROM dual;

DUMP(-123456,16)

---------------------------

Typ=2 Len=5: 3c,59,43,2d,66

SQL> SELECT DUMP(-1234567,16) FROM dual;

DUMP(-1234567,16)

------------------------------

Typ=2 Len=6: 3b,64,4e,38,22,66

SQL> SELECT DUMP(-12345678,16) FROM dual;

DUMP(-12345678,16)

------------------------------

Typ=2 Len=6: 3b,59,43,2d,17,66

SQL> SELECT DUMP(-123456789,16) FROM dual;

DUMP(-123456789,16)

--------------------------------

Typ=2 Len=7: 3a,64,4e,38,22,c,66

从上面的例子可以看出,在存储有效的非0数据时,每增加两位数,数据的存储空间就增加一个字节,直到数据溢出,这是因为oracle在存储时每一个字节会表示两位数。数据中的有效数字越多,那么占用的空间就会越大。

有了如上数据的感性认识之后,下面来看一下具体的存储算法:

正数计算方法:

第一步:得到一个最大指数N=F-193;(F代表第一个字节的数据)

第二步:从第二个字节开始,得到每一个字节的数ai,并减1;

第三步:依次计算(ai – 1)*100^(N-i);

第四步:将第三步的各个数据相加。

用一个示例来演示一把:

SQL>SELECTDUMP(123.123)DAFROM dual;

       DA

Typ=2 Len=5: 194,2,24,13,31

a) 得到一个最大的指数:N= F-193=194-193=1;

b) 从第二个字节开始,得到每一个字节的数ai,并减1;

  得到的数据依次为2-1,24-1,13-1,31-1 即1,23,12,30

c) 依次计算(ai – 1)*100^(N-i+1);

  得到的数据依次为:1*100^(1-1+1),23*100^(1-2+1), 12*100^(1-3+1), 30*100^(1-4+1)

  即:100,23,0.12,0.003

d) 将上面的几个数据依次相加得到结果。

100+23+0.12+0.003=123.123

OK,就是上面这样一个步骤来计算正数的。

对于负数的计算,算法如下:

第一步:得到一个最大指数N=62-F;(F代表第一个字节的数据)

第二步:从第二个字节开始,得到每一个字节的数ai,并用101减去ai

第三步:依次计算(101-ai)*100^(N-i);

第四步:将上面的几个数据依次相加得到结果。

注:

(1)  对于数字0,oracle只用了1个字节来进行存储,及十进制的128;

(2) 上面的算法有兴趣可以仔细去研究一下,为什么会存在一些“奇异的数据”,比如说193,62等;

 

4  Date:定长的7字节数据,分别表示世纪,年,月,日,时,分,秒

通过如下的实验来验证一把:

SQL>createTABLE t_test(aDATE);

SQL>INSERTINTO t_test(a)VALUES(SYSDATE);

SQL>COMMIT;

SQL>SELECTDUMP(t.a,16) DA FROM t_test t;

    DA

Typ=12 Len=7: 78,70,c,e,10,2c,3c

注:

a) 上面的查询输出中世纪和年的表示稍微复杂一点。Oracle将世纪和年的值各自都加了100来保存。比如上面的值是这样解读的:

世纪:十六进制78—>十进制是120,该值减去100即20,表示当前是第20世纪;

年:十六进制70-->十进制是112,该值减去100即12,表示当前是第12年;

对于公元前的数据一样的解析。

b) oracle的时间表示范围是公元前4712年1月1日到公元9999年12月31日

 

5  timstamp类型和raw类型在当前项目中用得不多,没有仔细去研究。

a) timestamp类型与date类型类似,只是精度更高,可能会占用更多的位。

b) raw类型的存储比较简单,所见即所得。

SQL> SELECT hextoraw('ff') FROM dual;

HEXTORAW('FF')

--------------

FF

SQL> SELECT hextoraw('ffee') FROM dual;

HEXTORAW('FFEE')

----------------

FFEE

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值