您的位置:首页 > 数据库 > Oracle

Oracle基础数据的存储格式

2013-04-26 20:47 417 查看
本文对日常开发过程中常遇到的几种基础数据类型在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,
bd2f
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: