【inernal】oracle中number类型存储解析

时间:2024-05-19 12:13:51

首先需要回答的两个问题。

1、number类型跟指定精度的number类型相比是否浪费存储空间?

   number类型不指定精度即相当于设置了number的最大精度(38位)。

   number类型的实际存储机制与varchar雷同,即存储多少数据占用多少空间。

   number类型下存储的23.23和number(9,3)下存储的23.23都是一样的。

   所以绝大多数情况下number类型和指定精度的number类型在存储空间上无区别。

  

   但存储无限小数就不同了。比如1/3.

   存储在number类型,会保留38位精度的小数(0.33333333333333333333333333333333333333)。

   存储在number(9,3)类型中,则会是(0.333)

   两者存储的数据本身不同,占用的空间自然就不同了。

2、若是存储数据超过列定义时指定的精度,oracle会如何处理?

   高位不够存储会报错。

   低位不够存储则四舍五入。

3、关于int、decimal等数字类型

    oracle支持int、decimal等类型,但仅仅是为了兼容其他数据库,实际oracle在内部使用和存储的时候,这些类型都会是number类型。

 

回答了以上两个问题就可以实际验证下了。

 

说下定义

number(precision,scale)

1、precision即有效数位,取值范围为【1--38】。可以理解存储数的长度(第一个非零开始到最后一个非零结束)

    从后面的存储部分可以知道,每1byte存储两位,38位共需要19byte的存储空间。

2、scale即比例,取值范围为【-84--127】,是小数点后保留的长度。可以为负,标识小数点前舍入的长度。

    从后面的存储部分可以知道,scale对应的最高位标识,使用了1byte(8位)存储,所以取值范围为-84--127.

3、若插入数据不符合规则定义,

    对于高位不够存储的,会报错。

   对于低位不够存储的,则四舍五入。

4、可插入的整数部分最大长度为(从正数部分第一个不为0的数位到各位,与precision中的存储长度区别下)为precision- scale。

   比如我存储1230(长度为4)到number(4,1)则会报错,因为4-1=3>4.存储在number(3,-1)则没问题,因为3-(-1)=4=4.

 

 

说下存储

【inernal】oracle中number类型存储解析

1、number类型存储方式如上图,共分三个部分,最高位标识、数据部分和正负标识。

2、数字0只有最高标识位,为0x80。

3、最高位标识,占用1byte,标识数字的第一个不为0的数字的进制位(每一个标识位标识两个进制位)。

    正数和负数的最高标示为不同。

    正数标示为大于0x80的数字,负数标示为小于0x80的数字。

        对于正数

        个位、十位标示为c1,百位、千位标示为c2.....

   十分位、百分位标示为c0,千分位、万分位标识位bf....

   对于负数

         ........具体可见下图。

【inernal】oracle中number类型存储解析

   

4、数据部分

     数据部分每1byte标识2位数。所以每1byte标识的数字范围为1-99.

     正数和负数的数字表示不同,

        对于正数,0x01--0x64(正序)标识1-99,其中0x标识比数字实际对应的十六进制数大1.比如0x02标识数字1,0x03标识数字2。

        对于负数,0x65--0x2(倒序)标识1-99,其中0x64标识数字1,0x63标识数字2.

5、符号位

       正数符号位为空,负数的符号位存储为0x66。

       经验证,只有当输入有效数字的长度大于38的时候,负数标识66将不存在(最高标识位可判断正负,所以这里我理解这个66是作了一个正负标识的冗余)。

说下验证方法

     对于不超过38位精度的数字,可以使用dump查看存储

         select dump(to_number(1),16) from dual;

 

        对于超过38位精度的数,就只能dump数据块查看了。

         alter systemdump datafile 1 block 123;