從DUMP函數(shù)說(shuō)開(kāi)去
?
?
??? 因?yàn)樽罱芯孔址詫?duì)于Oracle內(nèi)部的一些存儲(chǔ)模式產(chǎn)生了一些興趣,據(jù)說(shuō)DUMP這個(gè)函數(shù)的功能非常強(qiáng)大,所以專門研究了一下。當(dāng)然研究的都比較初級(jí),只是了解一下。具體哪里可以用到暫時(shí)還不知道 -_-||| ,另外對(duì)字符集的轉(zhuǎn)換等一些函數(shù)也了解一下:
?
?
一、函數(shù)用法
?
??? 函數(shù)的標(biāo)準(zhǔn)格式是:DUMP(expr[,return_fmt[,start_position][,length]])
?
??? 基本參數(shù)時(shí)4個(gè),最少可以填的參數(shù)時(shí)0個(gè),當(dāng)完全沒(méi)有參數(shù)時(shí),直接返回null。另外3個(gè)參數(shù)也都有各自的默認(rèn)值,一個(gè)一個(gè)來(lái)看:
?
??? expr:這個(gè)參數(shù)是要進(jìn)行分析的表達(dá)式(數(shù)字或字符串等,可以是各個(gè)類型的值)
??? return_fmt:指返回參數(shù)的格式,這個(gè)參數(shù)有5種用法
??????? 1) 8:以8進(jìn)制返回結(jié)果的值
??????? 2) 10:以10進(jìn)制返回結(jié)果的值(默認(rèn))
??????? 3) 16:以16進(jìn)制返回結(jié)果的值
??????? 4) 17:以單字符的形式返回結(jié)果的值
??????? 5) 1000:以上4種加上1000,表示在返回值中加上當(dāng)前字符集
??? start_position:開(kāi)始進(jìn)行返回的字符位置
??? length:需要返回的字符長(zhǎng)度
?
?
舉幾個(gè)例子:
?
SQL> SELECT DUMP('abc') FROM DUAL;
?
DUMP('ABC')
----------------------
Typ=96 Len=3: 97,98,99
?
SQL> SELECT DUMP('abc',16) FROM DUAL;
?
DUMP('ABC',16)
----------------------
Typ=96 Len=3: 61,62,63
?
SQL> SELECT DUMP('abc',1016) FROM DUAL;
?
DUMP('ABC',1016)
----------------------------------------
Typ=96 Len=3 CharacterSet=UTF8: 61,62,63
?
SQL> SELECT DUMP('abc',17,2,2) FROM DUAL;
?
DUMP('ABC',17,2,2)
------------------
Typ=96 Len=3: b,c
?
DUMP('ABC')
----------------------
Typ=96 Len=3: 97,98,99
?
SQL> SELECT DUMP('abc',16) FROM DUAL;
?
DUMP('ABC',16)
----------------------
Typ=96 Len=3: 61,62,63
?
SQL> SELECT DUMP('abc',1016) FROM DUAL;
?
DUMP('ABC',1016)
----------------------------------------
Typ=96 Len=3 CharacterSet=UTF8: 61,62,63
?
SQL> SELECT DUMP('abc',17,2,2) FROM DUAL;
?
DUMP('ABC',17,2,2)
------------------
Typ=96 Len=3: b,c
?
?
二、結(jié)果分析
?
??? 結(jié)果的格式一般都是類似: typ=96 Len=3 [CharacterSet=UTF8]: 61,62,63
?
??? 1、type
?
??? 其中typ表示了當(dāng)前的expr值的類型,例如2表示NUMBER,96表示CHAR等等。
??? 具體的所有格式列表在SQL Reference文檔中沒(méi)有找到,但是在網(wǎng)上找到了,網(wǎng)址:http://vongates.itpub.net/post/2553/17275
?
CODE TYP
----- ------------------------------
??? 1 VARCHAR2
??? 2 NUMBER
??? 8 LONG
?? 12 DATE
?? 23 RAW
?? 24 LONG RAW
?? 69 ROWID
?? 96 CHAR
? 112 CLOB
? 113 BLOB
? 114 BFILE
? 180 TIMESTAMP
? 181 TIMESTAMP WITH TIMEZONE
? 182 INTERVAL YEAR TO MONTH
? 183 INTERVAL DAY TO SECOND
? 208 UROWID
? 231 TIMESTAMP WITH LOCAL TIMEZONE
----- ------------------------------
??? 1 VARCHAR2
??? 2 NUMBER
??? 8 LONG
?? 12 DATE
?? 23 RAW
?? 24 LONG RAW
?? 69 ROWID
?? 96 CHAR
? 112 CLOB
? 113 BLOB
? 114 BFILE
? 180 TIMESTAMP
? 181 TIMESTAMP WITH TIMEZONE
? 182 INTERVAL YEAR TO MONTH
? 183 INTERVAL DAY TO SECOND
? 208 UROWID
? 231 TIMESTAMP WITH LOCAL TIMEZONE
?
??? 具體可以從USER_TAB_COLS視圖的定義中獲取這個(gè)方法:
?
select text from dba_views where view_name = 'USER_TAB_COLS';
?
??? 2、Len
?
??? Len表示該值所占用的字節(jié)數(shù)。
?
??? 這個(gè)沒(méi)有什么好解釋的,但是有時(shí)我們也可以使用這個(gè)特性發(fā)現(xiàn)一些問(wèn)題,例如:
?
SQL> select value from v$nls_parameters where parameter='NLS_CHARACTERSET';
?
VALUE
----------------------------------------------------------------
UTF8
?
SQL> select dump('多多',1010) from dual;
?
DUMP('多多',1010)
-------------------------------------------------------
Typ=96 Len=6 CharacterSet=UTF8: 229,164,154,229,164,154
?
?
VALUE
----------------------------------------------------------------
UTF8
?
SQL> select dump('多多',1010) from dual;
?
DUMP('多多',1010)
-------------------------------------------------------
Typ=96 Len=6 CharacterSet=UTF8: 229,164,154,229,164,154
?
?
SQL> conn wxq/wxq@win10gr2
?
SQL> select value from v$nls_parameters where parameter='NLS_CHARACTERSET';
?
VALUE
----------------------------------------------------------------
ZHS16GBK
?
SQL> select dump('多多',1010) from dual;
?
DUMP('多多',1010)
---------------------------------------------------
Typ=96 Len=4 CharacterSet=ZHS16GBK: 182,224,182,224
?
??? 可以看到,UTF8對(duì)于漢字來(lái)說(shuō),需要3個(gè)字節(jié)來(lái)存儲(chǔ)1個(gè)漢字,而我們常用的ZHS16GBK只需要2個(gè)字節(jié)。
?
?
??? 3、Value
?
??? 最后就是具體的存儲(chǔ)值了,這里的講究就比較多了,不是幾句話就能夠講得清楚的,更何況我自己就不清楚。恩,簡(jiǎn)單得來(lái)說(shuō),這些返回的數(shù)值就是Oracle在自己內(nèi)部對(duì)前面的這個(gè)expr值的存儲(chǔ)形式。對(duì)于非漢字的普通字符串,可以理解為就是它的ASCII碼(字符集中的編碼值)。可以舉個(gè)例子證明一下:
?
SQL> select dump('a=?5') from dual;
?
DUMP('A=?5')
-------------------------
Typ=96 Len=4: 97,61,63,53
SQL> SELECT CHR(97),CHR(61),CHR(63),CHR(53) FROM DUAL;
?
CHR(97) CHR(61) CHR(63) CHR(53)
------- ------- ------- -------
a?????? =?????? ??????? 5
?
SQL> SELECT ASCII('a'),ASCII('='),ASCII('?'),ASCII('5') FROM DUAL;
?
ASCII('A') ASCII('=') ASCII('?') ASCII('5')
---------- ---------- ---------- ----------
??????? 97???????? 61???????? 63???????? 53
?
DUMP('A=?5')
-------------------------
Typ=96 Len=4: 97,61,63,53
SQL> SELECT CHR(97),CHR(61),CHR(63),CHR(53) FROM DUAL;
?
CHR(97) CHR(61) CHR(63) CHR(53)
------- ------- ------- -------
a?????? =?????? ??????? 5
?
SQL> SELECT ASCII('a'),ASCII('='),ASCII('?'),ASCII('5') FROM DUAL;
?
ASCII('A') ASCII('=') ASCII('?') ASCII('5')
---------- ---------- ---------- ----------
??????? 97???????? 61???????? 63???????? 53
?
??? 而對(duì)于漢字的存儲(chǔ),就不太好測(cè)試了,而且也沒(méi)有搞清楚原理,應(yīng)該是直接套用字符集的漢字編碼規(guī)則的。
?
??? 對(duì)于數(shù)字的存儲(chǔ),并不像字符那么簡(jiǎn)單,而是應(yīng)用了Oracle自己的一個(gè)算法,eygle有過(guò)很詳細(xì)的說(shuō)明:
??? 具體的算法原理可以參見(jiàn)eygle的這篇文章:http://www.eygle.com/archives/2005/12/how_oracle_stor.html
?
?
三、關(guān)于其他
?
??? 順帶介紹一下怎么查找
Oracle對(duì)字符集類型的編碼(dump文件的前2個(gè)字節(jié)):
?
??? SELECT NLS_CHARSET_NAME(1) FROM DUAL;? --返回?cái)?shù)值對(duì)應(yīng)的字符集名稱
??? SELECT NLS_CHARSET_ID('US7ASCII') FROM DUAL;? --返回字符集對(duì)應(yīng)的數(shù)值
??? SELECT NLS_CHARSET_ID('US7ASCII') FROM DUAL;? --返回字符集對(duì)應(yīng)的數(shù)值
?
?
?
?
?
附:dump函數(shù)對(duì)number的存儲(chǔ)表示
--------------------------------------------------------------------------------
How Oracle Store Number internal?
作者:eygle |English Version 【轉(zhuǎn)載時(shí)請(qǐng)以超鏈接形式標(biāo)明文章出處和作者信息及本聲明】
鏈接: http://www.eygle.com/archives/2005/12/how_oracle_stor.html
--------------------------------------------------------------------------------
作者:eygle |English Version 【轉(zhuǎn)載時(shí)請(qǐng)以超鏈接形式標(biāo)明文章出處和作者信息及本聲明】
鏈接: http://www.eygle.com/archives/2005/12/how_oracle_stor.html
--------------------------------------------------------------------------------
Oracle在數(shù)據(jù)庫(kù)內(nèi)部通過(guò)相應(yīng)的算法轉(zhuǎn)換來(lái)進(jìn)行數(shù)據(jù)存儲(chǔ),本文簡(jiǎn)單介紹Oracle的Number型數(shù)值存儲(chǔ)及轉(zhuǎn)換.這個(gè)內(nèi)容是為了回答留言板上的2119號(hào)問(wèn)題.
?
我們可以通過(guò)DUMP函數(shù)來(lái)轉(zhuǎn)換數(shù)字的存儲(chǔ)形式,一個(gè)簡(jiǎn)單的輸出類似如下格式:
?
SQL> select dump(1) from dual;
DUMP(1)
------------------
Typ=2 Len=2: 193,2
?
DUMP函數(shù)的輸出格式類似:
?
類型 <[長(zhǎng)度]>,符號(hào)/指數(shù)位 [數(shù)字1,數(shù)字2,數(shù)字3,......,數(shù)字20]
?
各位的含義如下:
?
1.類型: Number型,Type=2 (類型代碼可以從Oracle的文檔上查到)
?
2.長(zhǎng)度:指存儲(chǔ)的字節(jié)數(shù)
?
3.符號(hào)/指數(shù)位
?
在存儲(chǔ)上,Oracle對(duì)正數(shù)和負(fù)數(shù)分別進(jìn)行存儲(chǔ)轉(zhuǎn)換:
?
正數(shù):加1存儲(chǔ)(為了避免Null)
負(fù)數(shù):被101減,如果總長(zhǎng)度小于21個(gè)字節(jié),最后加一個(gè)102(是為了排序的需要)
負(fù)數(shù):被101減,如果總長(zhǎng)度小于21個(gè)字節(jié),最后加一個(gè)102(是為了排序的需要)
?
指數(shù)位換算:
?
正數(shù):指數(shù)=符號(hào)/指數(shù)位 - 193 (最高位為1是代表正數(shù))
負(fù)數(shù):指數(shù)=62 - 第一字節(jié)
負(fù)數(shù):指數(shù)=62 - 第一字節(jié)
?
4.從<數(shù)字1>開(kāi)始是有效的數(shù)據(jù)位
?
從<數(shù)字1>開(kāi)始是最高有效位,所存儲(chǔ)的數(shù)值計(jì)算方法為:
?
將下面計(jì)算的結(jié)果加起來(lái):
?
每個(gè)<數(shù)字位>乘以100^(指數(shù)-N) (N是有效位數(shù)的順序位,第一個(gè)有效位的N=0)
?
5. 舉例說(shuō)明
?
SQL> select dump(123456.789) from dual;
DUMP(123456.789)
-------------------------------
Typ=2 Len=6: 195,13,35,57,79,91
?
<指數(shù)>:?? 195 - 193 = 2
<數(shù)字1>??? 13 - 1??? = 12 *100^(2-0) 120000
<數(shù)字2>??? 35 - 1??? = 34 *100^(2-1) 3400
<數(shù)字3>??? 57 - 1??? = 56 *100^(2-2) 56
<數(shù)字4>??? 79 - 1??? = 78 *100^(2-3) .78
<數(shù)字5>??? 91 - 1??? = 90 *100^(2-4) .009
??????????????????????????? 123456.789
?
SQL> select dump(-123456.789) from dual;
DUMP(-123456.789)
----------------------------------
Typ=2 Len=7: 60,89,67,45,23,11,102
?
<指數(shù)>???? 62 - 60 = 2(最高位是0,代表為負(fù)數(shù))
<數(shù)字1> 101 - 89 = 12 *100^(2-0) 120000
<數(shù)字2> 101 - 67 = 34 *100^(2-1) 3400
<數(shù)字3> 101 - 45 = 56 *100^(2-2) 56
<數(shù)字4> 101 - 23 = 78 *100^(2-3) .78
<數(shù)字5> 101 - 11 = 90 *100^(2-4) .009
????????????????????????????? 123456.789(-)
?
現(xiàn)在再考慮一下為什么在最后加102是為了排序的需要,-123456.789在數(shù)據(jù)庫(kù)中實(shí)際存儲(chǔ)為
?
60,89,67,45,23,11
?
而-123456.78901在數(shù)據(jù)庫(kù)中實(shí)際存儲(chǔ)為
?
60,89,67,45,23,11,91
?
可見(jiàn),如果不在最后加上102,在排序時(shí)會(huì)出現(xiàn)-123456.789<-123456.78901的情況。
?
對(duì)于2119號(hào)提問(wèn),第一個(gè)問(wèn)題是:
?
1.請(qǐng)問(wèn)為什么193,2各代表什么意思?
?
從上面就可以看到答案了.
?
2.還有NUMBER數(shù)字類型為什么有2個(gè)字節(jié)的長(zhǎng)度呢?
?
對(duì)于這個(gè)問(wèn)題,我想我們應(yīng)該知道,所有數(shù)據(jù)類型最終在計(jì)算機(jī)里都以二進(jìn)制存儲(chǔ),實(shí)際上所謂的數(shù)據(jù)類型都是我們定義的.所以存儲(chǔ)只由算法決定.
?
所以這個(gè)問(wèn)題是不成立的.比如:
?
SQL> select dump(110) from dual;
DUMP(110)
---------------------
Typ=2 Len=3: 194,2,11
?
SQL> select dump(1100) from dual;
DUMP(1100)
-------------------
Typ=2 Len=2: 194,12
?
我們會(huì)看到,雖然1100>110,但是存儲(chǔ)上1100卻只占2字節(jié),而110卻占了3個(gè)字節(jié).
?
?
?