oracle數據類型--數值類型

NUMBE:Oracle NUMBER類型能以極大的精度存儲數值,具體來說,精度可達38位。其底層數據格式相似一種「封包小數「表示。Oracle NUMBER類型是一種變長格式,長度爲0~22字節。它能夠存儲小到10e-130、大到(但不包括)10e126的任何數值。
BINARY_FLOAT:這是一種IEEE固有的單精度浮點數。它在磁盤上會佔用5字節的存儲空間:其中4個固定字節用於存儲浮點數,另外還有一個長度字節。BINARY_FLOAT能存儲有6爲精度、範圍在~±1038.53的數值。
BINARY_DOUBLE:這是一種IEEE固有的雙精度浮點數。它在磁盤上會佔用9字節的存儲空間:其中8個固定字節用於存儲浮點數,還有一個長度字節。BINARY_DOUBLE能存儲有12.位精度、範圍在~±10308.25的數值。sql

Oracle NUMBER類型比BINARY_FLOAT和BINARY_DOUBLE類型的精度大得多,可是取值範圍卻遠遠小於BINARY_DOUBLE。也就是說,用NUMBER類型能夠很精確地存儲數值(有不少有效數字),可是用BINARY_FLOAT和BINARY_DOUBLE類型能夠存儲更小或更大的數值。下面舉一個簡單的例子,咱們將用不一樣的數據類型來建立一個表,查看給定相同的輸入時,各個列中會存儲什麼內容:函數

scott@ORCL>create table t
  2  ( num_col number,
  3     float_col binary_float,
  4     dbl_col binary_double
  5  )
  6  /

表已建立。

scott@ORCL>insert into t ( num_col, float_col, dbl_col )
  2  values ( 1234567890.0987654321,
  3     1234567890.0987654321,
  4     1234567890.0987654321 );

已建立 1 行。

scott@ORCL>set numformat 99999999999.99999999999
scott@ORCL>select * from t;

                 NUM_COL                FLOAT_COL                  DBL_COL
------------------------ ------------------------ ------------------------
  1234567890.09876543210   1234567940.00000000000   1234567890.09876540000

NUM_COL會按咱們提供的輸入原樣返回同一個數。輸入數中有效數字遠遠沒有達到38位(這裏提供了一個有20位有效數字的數),因此將徹底保留原來的數。使用 BINARY_FLOAT類型時,FLOAT_COL不能準確地表示這個數。實際上,它只正確保留了7位。DBL_COL則要好多了,它正確地表示了這個數中的17位。由此能夠很好地說明BINARY_FLOAT和BINARY_DOUBLE類型在金融應用中不適用!若是嘗試不一樣的值,可能會看到不一樣的結果:工具

scott@ORCL>delete from t;

已刪除 1 行。

scott@ORCL>insert into t ( num_col, float_col, dbl_col )
  2  values ( 9999999999.9999999999,
  3     9999999999.9999999999,
  4     9999999999.9999999999 );

已建立 1 行。

scott@ORCL>select * from t;

                 NUM_COL                FLOAT_COL                  DBL_COL
------------------------ ------------------------ ------------------------
  9999999999.99999999990  10000000000.00000000000  10000000000.00000000000

NUM_COL又一次正確地表示了這個數,可是FLOAT_COL和DBL_COL卻未能作到。這並非說NUMBER類型能以「無限的「精度/準確性來存儲數據,它的精度只不過至關大而已(但並非無限的)。NUMBER類型也有可能不正確地表示數值,這種狀況很容易觀察到:性能

scott@ORCL>delete from t;

已刪除 1 行。

scott@ORCL>insert into t ( num_col )
  2  values ( 123 * 1e20 +  123*1e-20 ) ;

已建立 1 行。

scott@ORCL>set numformat 999999999999999999999999.999999999999999999999999
scott@ORCL>select num_col, 123*1e20, 123*1e-20 from t;

                                           NUM_COL
             123*1E20                                          123*1E-20
-------------------------------------------------- -----------------------------
--------------------- --------------------------------------------------
  12300000000000000000000.000000000000000000000000   12300000000000000000000.000
000000000000000000000                          .000000000000000001230000

若是把一個很是大的數(123 * 1e20)和一個很是小的數(123*1e-20)放在一塊兒,就會丟失精度,由於這個算術運算須要的精度不止38位。就較大數(123 * 1e20)自己而言,它能獲得「忠實「的表示,較小數(123*1e-20)也能精確地表示,可是較大數加上較小數的結果卻不能如實表示。這不僅是一個顯示/格式化的問題,能夠作如下驗證:spa

scott@ORCL>select num_col from t where num_col = 123*1e20;

                                           NUM_COL
--------------------------------------------------
  12300000000000000000000.000000000000000000000000

NUM_COL中的值等於 123 * 1e20,而不是咱們真正想插入的值。code

1 NUMBER類型的語法和用法

NUMBER( p,s )

在此P和S是可選的,用於指定:
精度(precision),或總位數。默認狀況下,精度爲38位,取值範圍是1~38之間。也能夠用字符*表示38。
小數位置(scale),或小數點右邊的位數。小數位數的合法值爲-48~127,其默認值取決因而否指定了精度。若是沒有指定精度,小數位數則默認有最大的取值區間。若是指定了精度,小數位數默認爲0.orm

應該把精度和小數位數考慮爲對數據的「編輯「,從某種程度上講它們能夠算是一種完整性工具。精度和小數位數根本不會影響數據在磁盤上如何存儲,而只會影響容許有哪些值以及數值如何舍入(round)。例如,若是某個值超過了所容許的精度,Oracle就會返回一個錯誤:ci

scott@ORCL>create table t ( num_col number(5,0) );

表已建立。

scott@ORCL>insert into t (num_col) values ( 12345 );

已建立 1 行。

scott@ORCL>insert into t (num_col) values ( 123456 );
insert into t (num_col) values ( 123456 )
                                 *
第 1 行出現錯誤:
ORA-01438: 值大於爲此列指定的容許精度

所以,可使用精度來保證某些數據完整性約束。在這個例子中,NUM_COL列不容許多於5位。字符串

另外一方面,小數位數能夠用於控制數值的「舍入「,例如:數學

scott@ORCL>create table t ( msg varchar2(12), num_col number(5,2) );

表已建立。

scott@ORCL>insert into t (msg,num_col) values ( '123.45', 123.45 );

已建立 1 行。

scott@ORCL>insert into t (msg,num_col) values ( '123.456', 123.456 );

已建立 1 行。

scott@ORCL>select * from t;

MSG                         NUM_COL
------------------------ ----------
123.45                       123.45
123.456                      123.46

儘管數值123.456超過了5位,但這一次插入成功了。這是由於,這個例子中利用小數位數將123.456「舍入「爲只有兩位小數,這就獲得了123.46,再根據精度來驗證123.46,發現知足精度要求,因此插入成功。不過,若是試圖執行如下插入,則會失敗:

scott@ORCL>insert into t (msg,num_col) values ( '1234', 1234 );
insert into t (msg,num_col) values ( '1234', 1234 )
                                             *
第 1 行出現錯誤:
ORA-01438: 值大於爲此列指定的容許精度

數值1234.00的位數超過了5位。指定小數位數爲2時,小數點左邊最多隻有3位,右邊有2位。所以,這個數不知足精度要求。NUMBER(5,2)列能夠存儲介於999.99~-999.99之間的全部值。

容許小數位數在-84~127之間變化,小數位數能夠爲負值 其做用是容許對小數點左邊的值舍入。就像NUMBER(5,2)將值舍入爲最接近0.01同樣,NUMBER(5,-2)會把數值舍入爲與之最接近的100,例如:

scott@ORCL>create table t ( msg varchar2(12), num_col number(5,-2) );

表已建立。

scott@ORCL>insert into t (msg,num_col) values ( '123.45', 123.45 );

已建立 1 行。

scott@ORCL>insert into t (msg,num_col) values ( '123.456', 123.456 );

已建立 1 行。

scott@ORCL>select * from t;

MSG                         NUM_COL
------------------------ ----------
123.45                          100
123.456                         100

這些數舍入爲與之最接近的100,精度仍是5位,可是如今小數點左邊容許有7位(包括尾部的兩個0):

scott@ORCL>insert into t (msg,num_col) values ( '1234567', 1234567 );

已建立 1 行。

scott@ORCL>select * from t;

MSG                         NUM_COL
------------------------ ----------
123.45                          100
123.456                         100
1234567                     1234600

scott@ORCL>insert into t (msg,num_col) values ( '12345678', 12345678 );
insert into t (msg,num_col) values ( '12345678', 12345678 )
                                                 *
第 1 行出現錯誤:
ORA-01438: 值大於爲此列指定的容許精度

精度指示了舍入後數值中容許有多少位,並使用小數位數來肯定如何舍入精度是一個完整性約束,而小數位數是一種「編輯「

NUMBER類型其實是磁盤上的一個變長數據類型,會佔用0~22字節的存儲空間。Oracle NUMBER類型與變長字符串很相似。下面經過例子來看看若是數中包含不一樣數目的有效數字會發生什麼狀況。咱們將建立一個包含兩個NUMBER列的表,並用分別有二、四、六、…、28位有效數字的多個數填充第一列。而後再將各個值分別加1,填充第二列:

scott@ORCL>create table t ( x number, y number );

表已建立。

scott@ORCL>insert into t ( x )
  2  select to_number(rpad('9',rownum*2,'9'))
  3  from all_objects
  4  where rownum <= 12;

已建立12行。

scott@ORCL>update t set y = x+1;

已更新12行。

下面使用內置VSIZE函數,它能顯示列佔用多大的存儲空間,從而能夠看到每行中兩個數的大小有怎樣的差別:

scott@ORCL>set numformat 99999999999999999999999999999
scott@ORCL>column v1 format 99
scott@ORCL>column v2 format 99
scott@ORCL>select x, y, vsize(x) v1, vsize(y) v2 from t order by x;

                             X                              Y  V1  V2
------------------------------ ------------------------------ --- ---
                            99                            100   2   2
                          9999                          10000   3   2
                        999999                        1000000   4   2
                      99999999                      100000000   5   2
                    9999999999                    10000000000   6   2
                  999999999999                  1000000000000   7   2
                99999999999999                100000000000000   8   2
              9999999999999999              10000000000000000   9   2
            999999999999999999            1000000000000000000  10   2
          99999999999999999999          100000000000000000000  11   2
        9999999999999999999999        10000000000000000000000  12   2
      999999999999999999999999      1000000000000000000000000  13   2

已選擇12行。

能夠看到,隨着X的有效數字數目的增長,須要愈來愈多的存儲空間。每增長兩位有效數字,就須要另一個字節的存儲空間。可是對各個數加1後獲得的數老是隻佔2個字節。Oracle存儲一個數時,會存儲儘量少的內容來表示這個數。爲此會存儲有效數字、用於指定小數點位置的一個指數,以及有關數值符號的信息(正或負)。所以,數中包含的有效數字越多,佔用的存儲空間就越大

2 BINARY_FLOAT/BINARY_DOUBLE類型的語法和用法

浮點數是一個有理數子集中一個數的數字表示,一般用於在計算機上近似一個任意的實數。特別是,它表示一個整數或浮點數(有效數,或正式地說法是尾數)乘以一個底數(在計算機中一般是2)的某個整數次冪(指數)。底數爲2時,這就是二進制的科學計數法(一般的科學計數法底數爲12)。

浮點數用於近似數值;它們沒有前面所述的內置Oracle NUMBER類型那麼精確。浮點數經常使用在科學計算中,因爲容許在硬件(CPU、芯片)上執行運算,而不是在Oracle子例程中運算,因此在多種不一樣類型的應用中都頗有用。所以,若是在一個科學計算應用中執行實數處理,算術運算的速度會快得多,不過你可能不但願使用浮點數來存儲金融信息。

要在表中聲明這種類型的列,語法至關簡單:

BINARY_FLOAT
BINARY_DOUBLE

3 非固有數據類型

除了NUMBER、BINARY_FLOAT和BINARY_DOUBLE類型,Oracle在語法上還支持如下數值數據類型:
NUMERIC(p,s):徹底映射至NUMBER(p,s)。若是p未指定,則默認爲38.
DECIMAL(p,s)或DEC(p,s):徹底映射至NUMBER(p,s)。若是p爲指定,則默認爲38.
INTEGER或INT:徹底映射至NUMBER(38)類型。
SMALLINT:徹底映射至NUMBER(38)類型。
FLOAT(b):映射至NUMBER類型。
DOUBLE PRECISION:映射至NUMBER類型。
REAL:映射至NUMBER類型。

「在語法上支持「,這是指CREATE語句可使用這些數據類型可是在底層實際上它們都只是NUMBER類型

4 性能考慮

通常而言,Oracle NUMBER類型對大多數應用來說都是最佳的選擇。不過,這個類型會帶來一些性能影響。Oracle NUMBER類型是一種軟件數據類型,在Oracle軟件自己中實現。咱們不能使用固有硬件操做將兩個NUMBER類型相加,這要在軟件中模擬。不過,浮點數沒有這種實現。將兩個浮點數相加時,Oracle會使用硬件來執行運算。

scott@ORCL>create table t
  2  ( num_type number,
  3     float_type binary_float,
  4     double_type binary_double
  5  )
  6  /

表已建立。

scott@ORCL>insert /*+ APPEND */ into t
  2  select rownum, rownum, rownum
  3  from all_objects
  4  /

已建立72114行。

scott@ORCL>commit;

提交完成。

再對各類類型的列執行一樣的查詢,在此使用一個複雜的數學函數,如NL(天然對數)。會觀察到它們的CPU利用率存在顯著差別:

select sum(ln(num_type)) from t
call count cpu elapsed
------- ------ -------- ----------
total 4 2.73 2.73
select sum(ln(float_type)) from t
call count cpu elapsed
------- ------ -------- ----------
total 4 0.06 0.12.
select sum(ln(double_type)) from t
call count cpu elapsed
------- ------ -------- ----------
total 4 0.05 0.12

Oracle NUMBER類型使用的CPU時間是浮點數類型的50倍。不過,從這3個查詢中獲得的答案並不徹底相同!浮點數是數值的一個近似值,精度在6~12位之間。從NUMBER類型獲得的答案比從浮點數獲得的答案「精確「得多。可是若是你在對科學數據執行數據挖掘或進行復雜的數值分析,這種精度損失每每是能夠接受的,另外可能會獲得很是顯著的性能提高。

須要注意,經過使用內置的CAST函數,能夠對Oracle NUMBER類型執行一種實時的轉換,在對其執行復雜數學運算以前先將其轉換爲一種浮點數類型。這樣一來,所用CPU時間就與使用固有浮點類型所用的CPU時間很是接近:

select sum(ln(cast( num_type as binary_double ) )) from t
call count cpu elapsed
------- ------ -------- ----------
total 4 0.12. 0.12.

能夠很是精確地存儲數據,若是須要提供速度,浮點類型則遠遠超過Oracle NUMBER類型,此時可使用CAST函數來達到提速的目標。

相關文章
相關標籤/搜索