oracle資料型別與儲存結構

sunwgneuqsoft發表於2007-09-29
Oracle 資料庫內建的資料型別主要有如下幾種:
。CHAR,NCHAR,VARCHAR2,NVARCHAR2
。NUMBER
。RAW
。LONG,LONG RAW
。DATE
。TIMESTAMP
。INTERVAL
。CLOB,BLOB,NCLOB,BFILE
。ROWID,UROWID
每種不同的資料型別用來儲存不同的資料,CHAR 儲存字元,NUMBER 儲存數值型。此外,每
種資料型別在資料塊中的儲存結構也是不一樣的,他們的儲存規則存在很大的區別,下面詳
細介紹一下每種資料型別在資料庫中的儲存結構,以及轉化的演算法。[@more@]Oracle 資料庫內建的資料型別主要有如下幾種:
。CHAR,NCHAR,VARCHAR2,NVARCHAR2
。NUMBER
。RAW
。LONG,LONG RAW
。DATE
。TIMESTAMP
。INTERVAL
。CLOB,BLOB,NCLOB,BFILE
。ROWID,UROWID
每種不同的資料型別用來儲存不同的資料,CHAR 儲存字元,NUMBER 儲存數值型。此外,每
種資料型別在資料塊中的儲存結構也是不一樣的,他們的儲存規則存在很大的區別,下面詳
細介紹一下每種資料型別在資料庫中的儲存結構,以及轉化的演算法。
1, 準備知識
SQL> create table test
2 (id varchar2(10),
3 score number(5,2));
Table created
SQL> insert into test values('a',78);
1 row inserted
SQL> insert into test values('b',85);
1 row inserted
SQL> commit;
Commit complete
SQL> select id,dump(id) from test;
ID DUMP(ID)
---------- --------------------------------------------------------------------------------
a Typ=1 Len=1: 97
b Typ=1 Len=1: 98
SQL> select score,dump(score) from test;
SCORE DUMP(SCORE)
------- --------------------------------------------------------------------------------
78.00 TYP=2Len=2: 193,79
85.00 TYP=2Len=2: 193,86
Oracle 在資料塊中並不是直接的不加修改的儲存我們的資料,而是進行一系列的轉化,以
一種更高效的方式來儲存。從上面的例子可以看出,字元“a”在資料塊中用“97”來表示
的,數值“78”是用“193,79”來儲存的。
注:dump 命令可以得到資料在資料庫中的儲存結構。Dump 的語法為dump(資料,進位制),
預設是轉化為10 進位制的。如果需要轉化為16 進位制,則語法為dump(資料,16)。
2, CHAR,NCHAR,VARCHAR2,NVARCHAR2
CHAR:字元型,單位元組,固定長度,最大為2000 個字元,內部編碼96
VARCHAR2:字元型,單位元組,可變長度,最大為4000 個字元,內部編碼1
NCHAR:字元型,多位元組,固定長度,最大為2000 個字元,內部編碼96
NARCHAR2:字元型,多位元組,可變長度,最大為4000 個字元,內部編碼1
1) CHAR
SQL> create table test_char
2 (a1 char(1),
3 a2 char(5));
Table created
SQL> insert into test_char values('a','ab');
1 row inserted
SQL> commit;
Commit complete
SQL> insert into test_char values('b’,’abc’);
1 row inserted
SQL> commit;
Commit complete
SQL> select a1,dump(a1) from test_char;
A1 DUMP(A1)--
--------------------------------------------------------------------------------
a Typ=96 Len=1: 97
b Typ=96 Len=1: 98
SQL> select a2,dump(a2) from test_char;
A2 DUMP(A2)
----- --------------------------------------------------------------------------------
ab Typ=96 Len=5: 97,98,32,32,32
abc Typ=96 Len=5: 97,98,99,32,32
從dump 的結果可以看到:
。CHAR 的型別編碼Typ 為96
。Len 表示該資料在資料庫中的儲存長度,char(1)為1,而char(5)為5
。“a”在資料庫的儲存格式為“97”,“b”為“98”
。“ab”在資料庫的儲存格式為“97,98,32,32,32”
。“abc”在資料庫的儲存格式為“97,98,99,32,32”
結論:
1, CHAR 的型別編碼Typ 為96
2, CHAR 在資料庫中按固定長度儲存,不足的為用空格補齊(chr(32))
3, 轉化規則
(1) 單位元組字元:資料庫中儲存的為資料的ascii 碼(1 個位元組)
SQL> select ascii('a') from dual;
ASCII('A')
----------
97
SQL> select ascii('b') from dual;
ASCII('B')
----------
98
(2) 多位元組字元:資料庫中儲存的為資料的ascii 碼(多個位元組)
SQL> select dump('好') from dual;
DUMP('好')
---------------------
Typ=96 Len=2: 186,195
SQL> select ascii('好') from dual;
ASCII('好')
-----------
47811
SQL> select 186*256 + 195 from dual;
186*256+195
-----------
47811
其中186 為高位,195 為低位,根據公式ascii 碼 = 高位*power(2,8)+ 低
位,所以'好'的ascii 為47811。
2) VARCHAR2
SQL> create table test_varchar2
2 (a1 varchar2(1),
3 a2 varchar2(5));
Table created
SQL> insert into test_varchar2 values ('a','ab');
1 row inserted
SQL> insert into test_varchar2 values ('b','abc');
1 row inserted
SQL> commit;
Commit complete
SQL> select a1,dump(a1) from test_varchar2;
A1 DUMP(A1)
-- --------------------------------------------------------------------------------
a Typ=1 Len=1: 97
b Typ=1 Len=1: 98
SQL> select a2,dump(a2) from test_varchar2;
A2 DUMP(A2)
----- --------------------------------------------------------------------------------
ab Typ=1 Len=2: 97,98
abc Typ=1 Len=3: 97,98,99
從dump 的結果可以看到:
。VARCHAR2 的型別編碼Typ 為1
。VARCHAR2 型別的資料在資料庫的儲存長度與實際插入的資料有關係,不需要補位
。“a”在資料庫的儲存格式為“97”,“b”為“98”
。“ab”在資料庫的儲存格式為“97,98,32,32,32”
。“abc”在資料庫的儲存格式為“97,98,99,32,32”
結論:
1, VARCHAR2 的型別編碼Typ 為1
2, VARCHAR2 在資料庫儲存就是資料的實際長度,不需要補位
3, 轉化規則:與CHAR 的轉化規則完全一致
另:NCHAR,NVARCHAR2 與CHAR,VARCHAR2 類似,就不一一介紹了。
結論
1, CHAR 與VARCHAR2 的最大的區別就是一個2000 位元組,一個4000 個位元組,還有就是一個
補足空位,一個不需要補空位
2, 一般說來資料庫能用CHAR 的地方都可以利用VARCHAR2 來代替,這樣可以節省資料庫的
空間。但是如果對效能有要求的系統來說,合理的使用CHAR 會比使用VARCHAR2 有更好
的效能。
3, NUMBER
SQL> create table test_number
2 (a1 number(8,2));
Table created
SQL> insert into test_number values (0);
1 row inserted
SQL> insert into test_number values (1);
1 row inserted
SQL> insert into test_number values (-1);
1 row inserted
SQL> insert into test_number values (0.12);
1 row inserted
SQL> insert into test_number values (34.56);
1 row inserted
SQL> insert into test_number values (-34.56);
1 row inserted
SQL> commit;
Commit complete
SQL> select a1 ,dump(a1) from test_number;
A1 DUMP(A1)
---------- --------------------------------------------------------------------------------
0.00 Typ=2 Len=1: 128
1.00 Typ=2 Len=2: 193,2
-1.00 Typ=2 Len=3: 62,100,102
0.12 Typ=2 Len=2: 192,13
34.56 Typ=2 Len=3: 193,35,57
-34.56 Typ=2 Len=4: 62,67,45,102
6 rows selected
從dump 的結果可以看到:
。NUMBER 的型別編碼Typ 為2
。如果數值為負數那麼需要在最後面補一位102,正數和零則不需要
。Len 為數值的實際值加上補位的長度
。數值0 在資料庫的儲存格式為128
。數值1 在資料庫的儲存格式為193,2
。數值-1 在資料庫的儲存格式為62,100,102
。數值0.12 在資料庫儲存格式為192,13
。數值34.56 在資料庫的儲存格式為193,35,56
。數值-34.56 在資料庫的儲存格式為62,67,45,102
結論:
1, NUMBER 的型別編碼Typ 為2
2, 如果數值為負數那麼需要在最後面補一位102,正數和零則不需要
之所以這樣處理,是為了更加方便的進行兩個數值的大小比較。Oracle 在進行資料庫中
兩個數值大小比較的時候,直接比較他們在資料庫中的儲存格式,並不是把他們轉化成
我們常用的數值形式後在比較。比如說:比較0和1 這兩個數,0 在資料庫中表示為128,
1 在資料庫中表示為193,2,那麼直接進行比較‘128’小於‘193’,所以0 肯定比1
要小。在比如說1 和0.12 這兩個數比較,0.12在資料庫中表示為192.13,因為‘193’
大於‘192’,所以1 肯定比0.12 大。這個規則對於正數和0 完全適用,但是對於不補
位的負數就要出麻煩了。看下面的例子:
SQL> select dump(-0.12) from dual;
DUMP(-0.12)
----------------------
Typ=2 Len=3: 63,89,102
SQL> select dump(-0.125) from dual;
DUMP(-0.125)
-------------------------
Typ=2 Len=4: 63,89,51,102
如果不補位的話-0.12 應該為63,89,而-0.125 應該為63,89,51,那麼按照前面的
規則來說‘63’等於‘63’,‘89’等於‘89’,‘51’肯定要大於空,就可以得出錯誤的
結論-0.12 小於-0.125。而當在負數後面補上102 後,情況就完全改變了,就可以很快
的得到正確的大小關係。
3, 轉化規則
(1)數值在資料庫中儲存結構的第一位叫做標誌位,是整個數值表示中最關鍵的一位。
如果標誌位大於128,那麼該數值為正數
如果標誌位等於128,那麼該數值為0
如果標誌位小於128,那麼該數值為負數
例如:
數值0 的標誌位為128,所以為0
數值0.12 的標誌位為192,所以0.12 為正數
數值-34.56 的標誌位為62,所以-34.56 為負數
(2)資料庫中儲存結構的除了第一位其餘的為數值位
如果該數值為正數,那麼每位上的實際數值等於資料庫中儲存的數值減1
如果該數值為負數,那麼每位上的實際數值等於101減去資料庫中儲存的數值,最
後補位的102 不用計算。
例如:
數值1 的數字為2 – 1 = 1
數值-1 的數字為 101 – 100 = 1
數值34.56 的數字為35 – 1 = 34,57 – 1 = 56,即3456
數值-34.56 的數字為101 – 67 = 34,101 – 45 = 56,即3456
(3)確定小數點位置
確定小數點的位置需要標誌位和第一位共同來決定
如果該數值為正數,那麼該數值的前幾位應該為第一位 * power(100,(標誌位 –
193))
如果該數值為負數,那麼該數值的前幾位應該為第一位 * power(100,(62–標誌
位))
例如:
34.56 Typ=2 Len=3: 193,35,57,該數值的前幾位應該為34*power(100,0)=34,
所以34.56 的小數點應該在4 的後面,那麼就可以得到該數值為34.56
-34.56 Typ=2 Len=4: 62,67,45,102該數值的前幾位應該為34*power(100,0)
=34,所以34.56 的小數點應該在4 的後面,那麼就可以得到該數值為-34.56
4, LONG
LONG 型別可變長度的字元型別,最高可以達到2G 個字元,可以在資料庫和使用者session的
字符集之間自動的轉化,內部編碼為8,oracle 建議使用LOB 型別代替LONG。
由於dump 不能對LONG 型的字元進行處理,所以這裡就不在舉例子說明了。LONG 型別的轉
化規則和其他字元型的類似。
下面著重說一下LONG 型別在資料表中的存放位置問題。
由於LONG 字元的特殊性,長度很大,所以一般當資料表中含有LONG型別的欄位時,oracle
都會盡可能的把它放到最後面來儲存,一來可以節省空間,二來可以提高效率。這裡面說的
是儘可能,有的時候oracle 無法做出相應的處理,LONG也可能位於中間位置,這時就需要
DBA 進行響應的調整了。
舉例1:
SQL> create table test_long_1
2 (a1 long,
3 a2 varchar2(10));
Table created
SQL> select object_id from dba_objects where object_name = 'TEST_LONG_1';
OBJECT_ID
---------
47383
SQL> select name,col#,segcol# from sys.col$ where obj# = '47383';
NAME COL# SEGCOL#
------------------------------ ---- -------
A1 1 2
A2 2 1
由上面的結果可以看到雖然LONG 型別的a1 首先被定義,但是在資料庫儲存的時候卻被放到
了a2 的後面。
注:COL#列表示資料表定義時候的順序,而SEGCOL#表示的是資料庫實際儲存的順序。
舉例2:
SQL> alter table test_long_1
2 add a3 number;
Table altered
SQL> select name,col#,segcol# from sys.col$ where obj# = '47383';
NAME COL# SEGCOL#
------------------------------ ---- -------
A1 1 2
A2 2 1
A3 3 3
如果表中已經存在了LONG 型別的欄位,那麼在新加入其他型別欄位時候就不會發生任何轉
化,此時LONG 型別的欄位在中間,這對效能會有很大的影響,這就需要DBA 來手工的進行
調整了。
5,DATE
DATE 型別提供關於世紀,年,月,日,小時,分和秒的資訊,不包含有小數的秒和時區信
息。DATE 的內部編碼為12。由固定的7 個位元組組成:
前兩位表示世紀和年,基數為100
下兩位表示月和日,基數為0
最後的三位是小時(24 小時制),分和秒,基數為1
SQL> create table test_date
2 (a1 date);
Table created
SQL> insert into test_date values(sysdate);
1 row inserted
SQL> commit;
Commit complete
SQL> select a1,dump(a1) from test_date;
A1 DUMP(A1)
-------------------------------------------------------------------------------
2006-5-29 2 Typ=12 Len=7: 120,106,5,29,22,33,41
世紀:120 – 100 = 20
年 :106 – 100 = 06
月 :5
日 :29
小時:22 – 1 = 21
分鐘:33 - 1 = 32
秒 :41 - 1 = 40
5, TIMESTAMP
TIMESTAMP 型別提供關於年,月,日,小時,分,帶有小數的秒的資訊。TIMESTAMP 的內部
編碼為180。
TIMESTAMP 由固定的11 個位元組組成:
前七個位元組與DATE 型別的一樣
後四個位元組表示秒的小數部分
SQL> create table test_stamp
2 (a1 timestamp);
Table created
SQL> insert into test_stamp values(systimestamp);
1 row inserted
SQL> commit;
Commit complete
SQL> select a1,dump(a1) from test_stamp;
A1 DUMP(A1)
-------------------------------------------------------------------------------
29-5月 -06 09.56.04.375000 Typ=180 Len=11: 120,106,5,29,22,57,5,22,90,11,192
世紀:120 – 100 = 20
年 :106 – 100 = 06
月 :5
日 :29
小時:22 – 1 = 21
分鐘:57 - 1 = 56
秒(整數):5 - 1 = 4
秒(小數):0.23440320
SQL> select to_char('22','xx') from dual;
TO_CHAR('22','XX')
------------------
16
SQL> select to_char('90','xx') from dual;
TO_CHAR('90','XX')
------------------
5a
SQL> select to_char('11','xx') from dual;
TO_CHAR('11','XX')
------------------
b
SQL> select to_char('192','xx') from dual;
TO_CHAR('192','XX')
-------------------
c0
SQL> select to_number('165abc0','xxxxxxxxxxx') from dual;
TO_NUMBER('165ABC0','XXXXXXXXX
------------------------------
23440320

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/8394333/viewspace-973776/,如需轉載,請註明出處,否則將追究法律責任。

相關文章