oracle数据类型存储结构

目标:
在oracle服务中确认数据类型的内部构造
解释数据类型在内部是如何存储的

内部存储知识
能更好的解释和分析块dumps
某些崩溃诊断必须的技能
帮助客户分析各种存储问题
是明白内部事务的必须步骤

oracle数据类型
数据类型包含:
  内置数据类型
  用户自定义数据类型
    结构型
      对象类型
    聚合型
      VARRAYS
      嵌套表
    引用类型(引用对象类型)
注意的是,oracle为程序提供了很多种数据类型,例如
  数字格式的:number,integer,float,decimal
  字符格式的:char,charz,string,varchar
内部数据类型从内部向外部自动的由oracle来转换.

内置数据类型
char,nchar,varchar2,nvarchar2
number
raw
long,long raw
date
datetime以及时间间隔类型
clob,blob,nclob,bfile
rowid,urowid
列中的数据取决于列的数据类型,但是数据类型并不是存储列数据的块中,本章以及后续课程将使用sql dump函数.范例中列的名字为TYP,关联的内部代码是各种数据类型,内部代码存储在数据字典中,在表col$的列type#下.

char和varchar2
字符类型数据通常是以数据库的字符集(单字节)存储的
char
  固定长度的字符串,最多2000字符;
  内部代码:96
varchar2
  浮动长度字符串,最多4000字符
  内部代码:1
为了能识别dump的输出文件,必须要知道他们存储的代码页.

char
在char类型的列中,所有的空字节被空格(代码32)填充
长度固定
由于char类型代码为96,长度固定,因此很容易分辨出那些是用来填充的空格

varchar2
varchar2列中,将不用空格填充.
长度不固定

nchar和nvarchar2
字符数据也可以使用国家字符集(多字节)设置存储
nchar
固定长度,最多2000字节
内部代码:96
nvarchar2
浮动长度,最多4000字节
内部代码:1

number
数字类型内部存储是一个字节的变长阿拉伯数字数组
数字类型有以下格式
< [length]>,sign bit/expornent,digit1,digit2,...,digit20
内部代码:2
注意的是,number和float有同样的内部特性.

指数类型
指数字节包含三个部分:
符号位:是整个字节的最高位(128)
  如果是0,则数字是负数
  如果是1,则数字是正数或者0
偏移量:总是65
指数:
  范围为-65到62
  标示该数字100为基础的科学记数法
如果指数是200=128+65+7,那么指数就是7,因此数据应该是大于100的7次方
如果一个数字是服侍,指数也同样的计算,但是要从255翻转,例如,一个指数为7的负数的计算是:-(125+65+7)=-(200)=255-200=77
偏移量使得负数的指数不需要使用别的字节来作为指数标志
如果第一个字节大于128,那么数字是正的:
exponent=first byte 128 -65=first bytes193
如果第一个字节小于128,那么数字是负的:
exponent=(255-first byte)-128-65=62-first byte

digits
大部分数字的最高位是digit1
使用100作为基数(每一个数字是0-99之间)
对于正数:
  对于每个digit使用进位(1…100)
对于负数:
  不是使用进位,而是从101减
  基数标志102(0×66)是最后的
数据库的进位中是没有0的,0标示数据结束.虽然现在该规则已经废除,但是为了兼容,还是保留.现在oracle通过计算长度来知道数据的结束.
存储是基于矢量对照语法的.从左边开始,比较数据的大小直到:
  一个部分不同,在这种情况下,最低的字节决定最小数字
  一个数据已经完成,在这种情况下,这个是两个数字中的最小的.
  所有的数据都比较完成,在这种情况下,两个数字相等
负数从101开始存储,因此比较下面的数字:
4=<193,5>,3=<193,4>比较这些字节,+4大于+3.
负数-4和-3.指数必须是62,如果值不是从101开始,则可能-4=<62,5>并且-3=<62,4>,这个时候,-4比-3大,显然是错误的.但是从101开始以后,数字就变成了-4=<62,97>并且-3=<62,98>.现在-3是比-4大的.
字节102附加在负数的后面,保证他们排序的正确性.比较数字-100<61,100,102>和-115<61,100,86,102>如果102不在这里,那么<61,100>和<61,100,86>将得到错误的结果,-100比-115小.

正数的例子:
因为数字是基于100的,因此最大的数字是99.指数从-65到62,因此,oracle的number的范围为:1*100(-65)=1*10(-120)到99*100(62)+99*100(61)... 无限接近1*10^(126)
但是,因为最大的精度是38,oracle将对超出精度的数据进行round操作.如果数字的字节数超过21,oracle就会报溢出
16进制也包括在这里面,因为在块dump中是一样的表现的
要注意第二个字节是如何增加和减少的,数字是基于100的.

正数的解读
数字为正数,第一个字节必须大于128(0×80)
第一步:指数=第一个字节-193
第二步:每一个其他的数字都减1
第三步:从基于100的指数转换到基于10的指数
       每一个结果通过100^(EXP-N)其中
       EXP是第一步中得到的指数
       N是数字的位置的顺序号(最高位的N=0)
第四步:将所有的值相加

负数的解读
数字为负数,第一个字节必须小于128(0×80)
第一步:指数=62-first bytes
第二步:每一个数字被101减
第三步:将基数从100转换为10
       每一个数字乘以100^(EXP-N)这里
       EXP是第一步中的指数值
       N是数字位置顺序值(最高位为0)
第四部:确认尾巴上的102已经抛弃
第五步:将所有的值相加
如果数字标示超过21字节,则最后的102不被要求,oracle不会使用22字节来标示的.oracle将自己会考虑所有的字节.

long
最大2GB大小的变长字符串
在数据库字符集和用户session字符集间自动转换(基于参数NLS_LANG的设置)
永远是内嵌存储
内部代码:8
推荐将long类型转换为lob类型
long列在表中是内嵌存储的.因此最好是最后一个列(性能的因素).但是用户还是可以在任何顺序指定long列的,但是oracle会自己在数据字典中组织数据,将long放到最后.因此在表COL$中,COL#是用户创的列的顺序,SEGCOL#是真实的存储顺序.
如果用户在创建了表以后,通过alert命令给表增加了列,则long列不会被存储在最后.oracle会自己算出重排数据的代价,并且将决定权交给dba.

RAW和long
raw二进制数据长度浮动,最多2000字节
内部代码:23
long raw
raw二进制数据浮动长度,最多2GB
内部代码24
在用户字符集和数据库字符集之间无法进行自动转换.
推荐使用lob列来代替long raw列
long raw列数据也是内嵌存储在表中的
raw和long raw是二进制内容,因此不需要转换为可打印的
例如,v$sqlarea是一个含有raw类型的列ADDRESS,注意,在sql层不会进行数据内容转换的.

date
date存储是固定的7个字节,世纪,年,月,日时分秒各占一个字节
  开始的两个字节存储世纪和年的基数是100
  接下来的两个字节是月和年(没有加任何数字的)
  最后三个字节是时(24小时制),分,秒(分别都加1了)
如果是作块的dump,要记得将数字从16进制转换为10进制.
有另外一个时间类型,内部代码13,有8个字节并且是被SYSDATE使用的

datetimes和intervals
在816中引入的新的数据类型
这些类型被称之为datatimes和intervals
  datetime数据类型提供一个点的时间的信息
  一个intereval行提供的是两个不同点的时间之间的信息
816中新的datetime类型:
TIME
TIME WITH TIME ZONE
TIMESTAMP
TIMESTAMP WITH TIME ZONE
TIMESTAMP WITH LOCAL TIME ZONE
816中新的interval类型:
INTERVAL YEAR TO MONTH
INTERVAL DAY TO SECOND
这些新的数据类型在816中并没有正式发布,因此是不被支持的,默认也是不可见的,向使用他们,必须设置事件:
event=”10406 trace name context forever”
event=”10407 trace name context forever”

time
该类型提供关于小时,分钟以及秒的9个数字精度的事件信息
固定长度是7字节数组
  前三个字节是HH24,MI,SS(这三个都加过1的)
  后四个字节是秒使用的(乘以10^9然后以16进制存储)
内部代码:178
假定一个time列有值为:03:50:30.123456789 PM
那么dump出来的是Type=178 Len=7 16,51,31,7,91,205,21
他们存储的是:
小时:16-1=15
分钟:51-1=50
秒:31-1=30
秒的精度部分  01 5B CD 15 ->123456789
也就是0.123456789秒

time with time zone
该类型提供关于小时,分,秒以及9个精度秒小数部分,时区小时和时区分钟
固定的是9个字节的数组
  开始的三个是HH24,MI,SS(每个都加了1)
  后面四个是秒
  最后两个是:
    时区小时(加20)
    时区分钟(加60)
内部代码:179

timestamp
该类型提供关于年,月,日,小时,分钟以及秒以及9位秒小数精度的信息
固定11字节长度数组
  开始7个和date类型相同
  最后4个是秒的精度
内部代码:180

timestamp with time zone
提供关于年,月,日,时汾秒以及9位秒小数精度,时区小时和时区分钟
固定13字节长度
  开始7个和date一样
  然后4个是秒的精度
  最后两个是时区小时和时区分钟
内部代码:181

timestamp with local time zone
提供年,月,日,小时,分钟和秒以及9位秒精度的信息的时间类型
固定11字节数组
  开始7个和date一样
  后面4个是秒的精度
列以session的时区作为时区
内部代码:231

interval year to month
提供两个时间点关于年和月的不同的信息
固定5个字节长度
  四个字节表示年(加上0×80000000)
  一个字节表示月(加上60)
偏移量加上是为了保证存储的是正数
内部代码:182

interval day to second
提供两个时间点不同的日,分以及秒
固定11个字节
  前四个表示日(加上0×80000000)
  小时,分,秒个用一个字节(加上60)
  四个字节表示秒的精度(加上0×80000000)
偏移量是为了保证值是正数
内部代码:183

sysdate
内部类型
固定8个字节长度
  世纪,年
  月,日
  小时,分,苗
  未使用的
内部代码:13
虽然SYSDATE是一个内部类型,并且不能被用于用户自己定义的列,但是在数据字典中用的很多,例如v$LOG,下面的查询可可解释SYSDATE的值
select dump(sysdate) from dual;
前面两个是存储的年,并且是平台有关的顺序的.我们称之为AA和BB
  在Sun上
  如果AA<128 YYYY=AA*256+BB
  如果AA>128 YYYY=(256-AA)*256+BB

rowid
是表中行记录的唯一的
三种格式:
  受限的短格式
    6个字节的16进制字符串
    DBA+Row(2字节)
  扩展格式
    10字节16进制字符串
    Object ID(4字节)+DBA+Row(2字节)
  普通的Rowid
短格式一般用在短以及过年包含了行所属的情况,例如行指针,非分区表上的普通索引以及分区表上的本地索引.
长格式包含对象号码,附加的表空间关联DBA这些是用来标示唯一行的.通常用在全局索引和分区表中.他们是符合DTYBRI类型的,并且用在用户自定义的rowid列中.
通用rowid,在8i中被引入,有三个子类型:物理的,逻辑的以及远程的,内部代码是208

urowid
在以下两种情况下标示行的逻辑地址
  索引组织表
  外部表
最大3950个字节的16进制字符串
三种格式
  物理
  逻辑的
  远程
内部代码:208

转自:http://www.oracledba.com.cn/blog/archives/239

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值