首先需要回答的两个问题。
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.
说下存储
1、number类型存储方式如上图,共分三个部分,最高位标识、数据部分和正负标识。
2、数字0只有最高标识位,为0x80。
3、最高位标识,占用1byte,标识数字的第一个不为0的数字的进制位(每一个标识位标识两个进制位)。
正数和负数的最高标示为不同。
正数标示为大于0x80的数字,负数标示为小于0x80的数字。
对于正数
个位、十位标示为c1,百位、千位标示为c2.....
十分位、百分位标示为c0,千分位、万分位标识位bf....
对于负数
........具体可见下图。
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;