oracle的number的浅析

author:skate

time:2011-02-14



oracle的number的浅析

从例如以下几个方面来认识number

1.表示的数值范围
   2.占用的存储空间
   3.number的性能

我们日常主要定义数值存储列是大都是用number,只是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类型。

以上这些类型仅仅是oracle在语法上支持的,在底层实际上还是number

1.表示的数值范围

NUMBER:Oracle NUMBER类型能以极大的精度存储数值,详细来讲,精度可达38位。其底层数据格式相似一种
       “封包小数“表示。Oracle NUMBER类型是一种变长格式,长度为0~22字节。它能够存储小到10e-130、
        大到(但不包含)10e126的不论什么数值。这是眼下最为经常使用的数值类型。也是Oracle9i Release 2及以
        前的版本号仅仅支持的唯一一种适合存储数值数据的固有数据类型,其它一起兼容类型仅仅是一种和number
        之间的映射,在底层实际上都是number

BINARY_FLOAT:这是一种IEEE固有的单精度浮点数。它在磁盘上会占用5字节的存储空间:当中4个固定字节用
              于存储浮点数,另外另一个长度字节。BINARY_FLOAT能存储有6为精度、范围在~±1038.53
              的数值

BINARY_DOUBLE:这是一种IEEE固有的双精度浮点数。它在磁盘上会占用9字节的存储空间:当中8个固定字节用
               于存储浮点数,另一个长度字节。BINARY_DOUBLE能存储有12.位精度、范围在~±10308.25的
               数值。

取值范举例:

创建測试表t2
SQL>  create table t2
  2   ( num_type number,
  3     float_type binary_float,
  4     double_type binary_double
  5   );

Table created

插入測试数据1
SQL>
SQL> insert into t2
  2    (num_type, float_type, double_type)
  3  values
  4    (1234567890.0987654321, 1234567890.0987654321, 1234567890.0987654321);

1 row inserted

查看測试数据1
SQL>
SQL>  select to_char(num_type),
  2          to_char(float_type, ‘999999999999.999999999‘),
  3          to_char(double_type, ‘99999999999.9999999999‘)
  4     from t2
  5  ;

TO_CHAR(NUM_TYPE)               TO_CHAR(FLOAT_TYPE,‘9999999999            TO_CHAR(DOUBLE_TYPE,‘999999999
--------------------------- -----------------------------------------------------------------------------------
1234567890.0987654321            1234567940.000000000                        1234567890.0987654000

插入測试数据2
SQL>
SQL> insert into t2
  2    (num_type, float_type, double_type)
  3  values
  4    (12345678900987654321, 12345678900987654321, 12345678900987654321);

1 row inserted

查看測试数据2
SQL>
SQL>  select to_char(num_type),
  2          to_char(float_type, ‘999999999999999999999‘),
  3          to_char(double_type, ‘999999999999999999999‘)
  4     from t2
  5  ;

TO_CHAR(NUM_TYPE)                        TO_CHAR(FLOAT_TYPE,‘9999999999                                                   TO_CHAR(DOUBLE_TYPE,‘999999999
---------------------------------------- -------------------------------------------------------------------------------- --------------------------------------------------------------------------------
1234567890.0987654321                                1234567940                                                                       1234567890
12345678900987654321                       12345679400000000000                                                             12345678900987654000

SQL>

从測试结果能够看到,number能够正确显示数据,精度非常高;binary_float仅仅正确的显示了前7位;binary_double显示的数据范围和精度要比binary_float高非常多。

2.占用的存储空间

number类型占用0-22个字节,它实际上是磁盘上的一个变长数据类型,是oracle依据一定算法,採用尽可能少存储空间表示一个数

SQL> create table t ( x number, y number );

Table created

SQL>
SQL>  insert into t ( x )
  2   select to_number(rpad(‘9‘,rownum*2,‘9‘),‘999999999999999999999999999999999999999999999999999999999‘)
  3   from all_objects
  4   where rownum <= 25;

25 rows inserted

SQL> update t set y = x+1;

25 rows updated

SQL> column 数字1 format 9999999999999999999999999999999999999999999999999999999999999999999999999

SQL> column 数字2 format 9999999999999999999999999999999999999999999999999999999999999999999999999

SQL>  select to_char(x) 数字1, to_char(y) 数字2, vsize(x) 数字1占字节数, vsize(y) 数字2占字节数 from t order by x;

数字1                                             数字2                                       数字1占字节数 数字2占字节数
----------------------------------------------- ------------------------------------------------------------------------- ------------- -------------
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
99999999999999999999999999                      100000000000000000000000000                    14             2
9999999999999999999999999999                    10000000000000000000000000000                  15             2
999999999999999999999999999999                  1000000000000000000000000000000                16             2
99999999999999999999999999999999                100000000000000000000000000000000              17             2
9999999999999999999999999999999999              10000000000000000000000000000000000            18             2
999999999999999999999999999999999999            1000000000000000000000000000000000000          19             2
99999999999999999999999999999999999999          100000000000000000000000000000000000000        20             2
9999999999999999999999999999999999999999        1.0000000000000000000000000000000000E+40       21             2

数字1                                                                     数字2               数字1占字节数 数字2占字节数
--------------------------------------------------------------------------------------------------- ------------- -------------
1.0000000000000000000000000000000000E+42         1.0000000000000000000000000000000000E+42      2             2
1.0000000000000000000000000000000000E+44         1.0000000000000000000000000000000000E+44      2             2
1.0000000000000000000000000000000000E+46         1.0000000000000000000000000000000000E+46      2             2
1.0000000000000000000000000000000000E+48         1.0000000000000000000000000000000000E+48      2             2
1.0000000000000000000000000000000000E+50         1.0000000000000000000000000000000000E+50      2             2

25 rows selected

SQL>

从样例能够看出,在oracle存储有效数据(非0数据)时,每添加两位数,数据的存储空间就添加一个字节,直到数据溢出。
Oracle存储一个数时,会存储尽可能少的内容来表示这个数。为此会存储有效数字和用于指定小数点位置的一个指数,以及
有关数值符号的信息(正或负)。因此,数中包括的有效数字越多,占用的存储空间就越大。

BINARY_FLOAT与BINARY_DOUBLE

浮点数用于近似数值;它们没有Oracle内置的 NUMBER类型那么精确。浮点数经常使用在科学计算中,因为同意在硬件(CPU、芯片)
上运行运算,而不是在Oracle子例程中运算,所以在多种不同类型的应用中都非常实用。因此,假设在一个科学计算应用中运行
实数处理,算术运算的速度会快得多。

BINARY_FLOAT在磁盘上会占用5字节的存储空间:当中4个固定字节用于存储浮点数,另外另一个长度字节
BINARY_DOUBLE在磁盘上会占用9字节的存储空间:当中8个固定字节用于存储浮点数,另外另一个长度字节

3.number的性能
Oracle NUMBER类型对大多数应用来讲都是最佳的选择,尤其是经融行业,只是有利必有弊,number会带来性能的影响。
由于Oracle NUMBER类型是一种软件数据类型,是在Oracle软件本身中实现。我们不能使用固有硬件操作将两个NUMBER
类型相加,这要在软件中模拟,所以性能有非常大的影响,为此,oracle又提供的两个浮点类型的BINARY_FLOAT与BINARY_DOUBLE。

以下举例说明性能对照

创建測试表
SQL>  create table t2
  2   ( num_type number,
  3     float_type binary_float,
  4     double_type binary_double
  5   );

Table created

SQL>
SQL>  insert /*+ APPEND */ into t2
  2   select rownum, rownum, rownum
  3   from all_objects
  4  ;

57302 rows inserted

SQL> alter session set events ‘10046 trace name context forever ,level 1‘;

Session altered

SQL>  select sum(ln(num_type)) from t2;

SUM(LN(NUM_TYPE))
-----------------
 570510.312356972

SQL>  select sum(ln(float_type)) from t2;

SUM(LN(FLOAT_TYPE))
-------------------
    570510.31235697

SQL>  select sum(ln(double_type)) from t2;

SUM(LN(DOUBLE_TYPE))
--------------------
     570510.31235697

SQL>  select sum(ln(cast(num_type as binary_double ) )) from t2;

SUM(LN(CAST(NUM_TYPEASBINARY_D
------------------------------
               570510.31235697

SQL> alter session set events ‘10046 trace name context off ‘;

Session altered

SQL>

查看跟踪文件内容例如以下:

........

********************************************************************************

select sum(ln(num_type))
from
 t2

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          3          1           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        1      2.31       2.25         38        193          0           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        3      2.31       2.25         38        196          1           1

********************************************************************************

select sum(ln(float_type))
from
 t2

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          1          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        1      0.04       0.04          0        193          0           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        3      0.04       0.04          0        194          0           1

********************************************************************************

select sum(ln(double_type))
from
 t2

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          1          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        1      0.03       0.04          0        193          0           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        3      0.04       0.04          0        194          0           1

********************************************************************************

select sum(ln(cast(num_type as binary_double ) ))
from
 t2

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          1          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        1      0.10       0.09          0        193          0           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        3      0.10       0.10          0        194          0           1

从測试结果来看,number的性能确实非常慢,比浮点类型BINARY_FLOAT与BINARY_DOUBLE慢57倍多,只是能够cast函数来转换下,
在对number运行复杂数学运算之前先将其转换为一种浮点数类型,这样就会提高计算速度,但还是比直接用浮点类型慢非常多,
但也是一个折中的方法。

--------end-------

时间: 2024-08-25 17:20:25

oracle的number的浅析的相关文章

ORACLE 中NUMBER 类型 低精度转换成高精度

例如: 表User中有一个字段 salary  Number(10,3), 如果想把字段salary的类型提高精度到salary  Number(10,6),保留六位小数, 解决办法:1,ALTER TABEL USER MODIFY SALARY NUMBER(13,6); 解释:number类型刚开始是,长度10位,3位小数,如果想增加3位小数,对应的长度也必须增加,否则无法修改.所以NUMBER(13,6);这样就可以提高精度了, ORACLE 中NUMBER 类型 低精度转换成高精度

对于Oracle中Number类型的字段映射成Java中的具体类型的问题

我在Oracle中给一个用户Id字段设置为Number类型,使用JDBC在完成ORM的时候,以为其可以自动转换为Integer,因为我的POJO类id舒心实用的就是Integer.但事实是,我在测试的时候,发现所有的用户id全为null,还在奇怪明明数据库中id是有值的,为什么取不到? 原因在于Oracle的Number类型映射为Java类型中的 java.math.BigDecimal (不可变的.任意精度的有符号十进制数)类型,并不是我简单认为的 Integer ,还会报一个错误: 就是说B

【转】oracle数据库NUMBER数据类型

原文:http://www.jb51.net/article/37633.htm NUMBER ( precision, scale)a)  precision表示数字中的有效位;如果没有指定precision的话,Oracle将使用38作为精度.b)  如果scale大于零,表示数字精确到小数点右边的位数:scale默认设置为0:如果scale小于零,Oracle将把该数字取舍到小数点左边的指定位数.c)  Precision的取值范围为[1---38]:Scale的取值范围为[-84---1

float和double的范围和精度,Oracle的Number类型

double.float都是浮点型.double(双精度型)比float(单精度型)存的数据更准确些,占的空间也更大.double精度是float的两倍,所以需要更精确的计算常使用double. 单精度浮点数在机内占4个字节,用32位二进制描述.双精度浮点数在机内占8个字节,用64位二进制描述. 浮点数在机内用指数型式表示,分解为:数符,尾数,指数符,指数四部分.数符占1位二进制,表示数的正负.指数符占1位二进制,表示指数的正负.尾数表示浮点数有效数字,0.xxxxxxx,但不存开头的0和点指数

oracle数据类型之number/char浅析

NUMBER: number:38位:number(p,s):p:精度,s:刻度(小数位数),在Oracle数据库中,number数据类型代表int,double,float等数字类型数据 举例: 1234.567 number(6,2) --------> 1234.57 0.001234 number(2,4) --------> 0.0012 number长度一般是0-22个字节,在Oracle中定义某列为number型,其列长度为22字节 CHAR/vVARCHAR/VARCHAR2:

Oracle嵌套表存储格式浅析

Oracle嵌套表很少用,下面来研究下其如何存储的.用一个例子,一个用户对应对个部门. SQL> select * from v$version; BANNER -------------------------------------------------------------------------------- Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production PL/SQL Rele

ORACLE 中NUMBER类型默认的精度和Scale问题

在ORACLE数据库中,NUMBER(P,S)是最常见的数字类型,可以存放数据范围为10^-130~10^126(不包含此值),需要1~22字节(BYTE)不等的存储空间.P 是Precison的英文缩写,即精度缩写,表示有效数字的位数,最多不能超过38个有效数字.S是Scale的英文缩写,表示从小数点到最低有效数字的位数,它为负数时,表示从最大有效数字到小数点的位数.有时候,我们在创建表的时候,NUMBER往往没有指定P,S的值,那么默认情况下,NUMBER的P.S的值分别是多少呢?相信这个问

oracle分页查询原理浅析

原因一 oracle默认为每个表生成rowmun,rowid字段,这些字段我们称之为伪列 1 创建测试表 CREATE TABLE TEST( ID NUMBER, NAME VARCHAR2(20) ) 2 插入测试数据 INSERT INTO TEST VALUES (1,'张三'); INSERT INTO TEST VALUES (2,'李四'); INSERT INTO TEST VALUES (3,'王五'); INSERT INTO TEST VALUES (4,'赵六'); IN

oracle数据类型number 为null 判断

number 可以是整数,也可以是含小数点的小数 操作项: a(number(18,2)),b(number(18,2)), +相加) 1.如果操作项有一个为 null, 相加结果为null ,a+null= null 2.正确写法:nvl(a,0)+nvl(b,0) sum 求和并相加)(sum求和 会自动把null值补0) 1.此写法结果错误: result1=sum(a+b) 2.此写法结果错误: result2= sum(a)+sum(b) .出错原因为:sum(null+null) =