從DUMP函數說開去
?
?
??? 因為最近研究字符集,所以對于Oracle內部的一些存儲模式產生了一些興趣,據說DUMP這個函數的功能非常強大,所以專門研究了一下。當然研究的都比較初級,只是了解一下。具體哪里可以用到暫時還不知道 -_-||| ,另外對字符集的轉換等一些函數也了解一下:
?
?
一、函數用法
?
??? 函數的標準格式是:DUMP(expr[,return_fmt[,start_position][,length]])
?
??? 基本參數時4個,最少可以填的參數時0個,當完全沒有參數時,直接返回null。另外3個參數也都有各自的默認值,一個一個來看:
?
??? expr:這個參數是要進行分析的表達式(數字或字符串等,可以是各個類型的值)
??? return_fmt:指返回參數的格式,這個參數有5種用法
??????? 1) 8:以8進制返回結果的值
??????? 2) 10:以10進制返回結果的值(默認)
??????? 3) 16:以16進制返回結果的值
??????? 4) 17:以單字符的形式返回結果的值
??????? 5) 1000:以上4種加上1000,表示在返回值中加上當前字符集
??? start_position:開始進行返回的字符位置
??? length:需要返回的字符長度
?
?
舉幾個例子:
?
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
?
?
二、結果分析
?
??? 結果的格式一般都是類似: typ=96 Len=3 [CharacterSet=UTF8]: 61,62,63
?
??? 1、type
?
??? 其中typ表示了當前的expr值的類型,例如2表示NUMBER,96表示CHAR等等。
?
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
?
??? 具體可以從USER_TAB_COLS視圖的定義中獲取這個方法:
?
select text from dba_views where view_name = 'USER_TAB_COLS';
?
??? 2、Len
?
??? Len表示該值所占用的字節數。
?
??? 這個沒有什么好解釋的,但是有時我們也可以使用這個特性發現一些問題,例如:
?
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
?
?
?
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對于漢字來說,需要3個字節來存儲1個漢字,而我們常用的ZHS16GBK只需要2個字節。
?
?
??? 3、Value
?
??? 最后就是具體的存儲值了,這里的講究就比較多了,不是幾句話就能夠講得清楚的,更何況我自己就不清楚。恩,簡單得來說,這些返回的數值就是Oracle在自己內部對前面的這個expr值的存儲形式。對于非漢字的普通字符串,可以理解為就是它的ASCII碼(字符集中的編碼值)。可以舉個例子證明一下:
?
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
?
??? 而對于漢字的存儲,就不太好測試了,而且也沒有搞清楚原理,應該是直接套用字符集的漢字編碼規則的。
?
??? 對于數字的存儲,并不像字符那么簡單,而是應用了Oracle自己的一個算法,eygle有過很詳細的說明:
?
?
三、關于其他
?
??? 順帶介紹一下怎么查找
Oracle對字符集類型的編碼(dump文件的前2個字節):
?
??? SELECT NLS_CHARSET_NAME(1) FROM DUAL;? --返回數值對應的字符集名稱
??? SELECT NLS_CHARSET_ID('US7ASCII') FROM DUAL;? --返回字符集對應的數值
?
?
?
?
?
附:dump函數對number的存儲表示
--------------------------------------------------------------------------------
Oracle在數據庫內部通過相應的算法轉換來進行數據存儲,本文簡單介紹Oracle的Number型數值存儲及轉換.這個內容是為了回答留言板上的2119號問題.
?
我們可以通過DUMP函數來轉換數字的存儲形式,一個簡單的輸出類似如下格式:
?
SQL> select dump(1) from dual;
DUMP(1)
------------------
Typ=2 Len=2: 193,2
?
DUMP函數的輸出格式類似:
?
類型 <[長度]>,符號/指數位 [數字1,數字2,數字3,......,數字20]
?
各位的含義如下:
?
1.類型: Number型,Type=2 (類型代碼可以從Oracle的文檔上查到)
?
2.長度:指存儲的字節數
?
3.符號/指數位
?
在存儲上,Oracle對正數和負數分別進行存儲轉換:
?
正數:加1存儲(為了避免Null)
負數:被101減,如果總長度小于21個字節,最后加一個102(是為了排序的需要)
?
指數位換算:
?
正數:指數=符號/指數位 - 193 (最高位為1是代表正數)
負數:指數=62 - 第一字節
?
4.從<數字1>開始是有效的數據位
?
從<數字1>開始是最高有效位,所存儲的數值計算方法為:
?
將下面計算的結果加起來:
?
每個<數字位>乘以100^(指數-N) (N是有效位數的順序位,第一個有效位的N=0)
?
5. 舉例說明
?
SQL> select dump(123456.789) from dual;
DUMP(123456.789)
-------------------------------
Typ=2 Len=6: 195,13,35,57,79,91
?
<指數>:?? 195 - 193 = 2
<數字1>??? 13 - 1??? = 12 *100^(2-0) 120000
<數字2>??? 35 - 1??? = 34 *100^(2-1) 3400
<數字3>??? 57 - 1??? = 56 *100^(2-2) 56
<數字4>??? 79 - 1??? = 78 *100^(2-3) .78
<數字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
?
<指數>???? 62 - 60 = 2(最高位是0,代表為負數)
<數字1> 101 - 89 = 12 *100^(2-0) 120000
<數字2> 101 - 67 = 34 *100^(2-1) 3400
<數字3> 101 - 45 = 56 *100^(2-2) 56
<數字4> 101 - 23 = 78 *100^(2-3) .78
<數字5> 101 - 11 = 90 *100^(2-4) .009
????????????????????????????? 123456.789(-)
?
現在再考慮一下為什么在最后加102是為了排序的需要,-123456.789在數據庫中實際存儲為
?
60,89,67,45,23,11
?
而-123456.78901在數據庫中實際存儲為
?
60,89,67,45,23,11,91
?
可見,如果不在最后加上102,在排序時會出現-123456.789<-123456.78901的情況。
?
對于2119號提問,第一個問題是:
?
1.請問為什么193,2各代表什么意思?
?
從上面就可以看到答案了.
?
2.還有NUMBER數字類型為什么有2個字節的長度呢?
?
對于這個問題,我想我們應該知道,所有數據類型最終在計算機里都以二進制存儲,實際上所謂的數據類型都是我們定義的.所以存儲只由算法決定.
?
所以這個問題是不成立的.比如:
?
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
?
我們會看到,雖然1100>110,但是存儲上1100卻只占2字節,而110卻占了3個字節.
?
?
?
?