没有合适的资源?快使用搜索试试~ 我知道了~
首页oracle基本数据类型存储格式浅析.pdf
资源详情
资源评论
资源推荐
Oracle 基本数据类型存储格式浅析(yangtingkun )
作者: yangtingkun
摘自: http://yangtingkun.itpub.net/category/468/1253
Oracle 基本数据类型存储格式浅析(一)——字符类型:http://blog.itpub.net/post/468/9287
Oracle 基本数据类型存储格式浅析(二)——数字类型:http://blog.itpub.net/post/468/9445
Oracle 基本数据类型存储格式浅析(三)——日期类型(一):http://blog.itpub.net/post/468/10113
Oracle 基本数据类型存储格式浅析(三)——日期类型(二):http://blog.itpub.net/post/468/10293
Oracle 基本数据类型存储格式浅析(三)——日期类型(三):http://blog.itpub.net/post/468/10582
Oracle 基本数据类型存储格式浅析(三)——日期类型(四):http://blog.itpub.net/post/468/13636
Oracle 基本数据类型存储格式浅析(四)——ROWID 类型(一):http://blog.itpub.net/post/468/11046
Oracle 基本数据类型存储格式浅析(四)——ROWID 类型(二):http://blog.itpub.net/post/468/11363
Oracle 基本数据类型存储格式浅析(五)——RAW 类型:http://blog.itpub.net/post/468/11490
Oracle 基本数据类型存储格式浅析(一)——字符类型
前一阵看完文档,对 oracle 的基本数据类型的存储格式有了一些了解,最近有做了一些测试进行了验证。打算整理总结一下,这一
篇主要说明字符类型的存储格式。主要包括 char、varchar2 和 long 等几种类型。
SQL> create table test_char (char_col char(10), varchar_col varchar2(10), long_col long);
表已创建。
SQL> insert into test_char values ('abc', '123', ',fd');
已创建 1 行。
SQL> commit;
提交完成。
SQL> select rowid from test_char;
ROWID
----------------------------
AAAB3LAAFAAAAAgAAA
根据 rowid 的定义规则,第 7~9 位是表示的是数据文件,F 表示 5,而 10~15 位表示的是在这个数据文件中的第几个 BLOCK,g 表示
32。(rowid 编码相当于 64 进制。用 A~Z a~z 0~9 + /共 64 个字符表示。A 表示 0,B 表示 1,……,a 表示 26,……,0 表示 52,……,
+表示 62,/表示 63。)
整理注:方便查看,附上一个对照表
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
a b c d e f g h i j k l m n o p q r s t u v w x y z
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 5051
0 1 2 3 4 5 6 7 8 9 + /
52 53 54 55 56 57 58 59 60 61 62 63
我们根据计算的结果去 dump 这个 block。
SQL> ALTER SYSTEM DUMP DATAFILE 5 BLOCK 32;
系统已更改。
打开产生的 trace 文件:
data_block_dump,data header at 0x3421064
===============
tsiz: 0x1f98
hsiz: 0x14
pbl: 0x03421064
bdba: 0x01400020
76543210
flag=--------
ntab=1
nrow=1
frre=-1
fsbo=0x14
fseo=0x1f82
avsp=0x1f6e
tosp=0x1f6e
0xe:pti[0] nrow=1 offs=0
0x12:pri[0] offs=0x1f82
block_row_dump:
tab 0, row 0, @0x1f82
tl: 22 fb: --H-FL-- lb: 0x1 cc: 3
col 0: [10] 61 62 63 20 20 20 20 20 20 20
col 1: [ 3] 31 32 33
col 2: [ 3] 2c 66 64
end_of_block_dump
End dump data blocks tsn: 5 file#: 5 minblk 32 maxblk 32
观察 dump 出来的结果,可以发现以下几点:
1.对于每个字段,除了保存字段的值以外,还会保存当前字段中数据的长度。而且,oracle 显然没有把字段的长度定义或类型定义保存在
block 中,这些信息保存在 oracle 的数据字典里面。
疑惑:我的 trc 文件中怎么没有上面红色文字那段?
知识补充:
DUMP returns a VARCHAR2 value containing the datatype code, length in bytes, and internal representation of
expr. The returned result is always in the database character set.
2. 根据 dump 的结果,可以清楚的看到,字符类型在数据库中是以 ascii 格式存储的。
SQL> select chr(to_number('61', 'xx')) from dual;
CH
--
a
3.char 类型为定长格式,存储的时候会在字符串后面填补空格,而 varchar2 和 long 类型都是变长的。
SQL> SELECT DUMP(CHAR_COL, 16) D_CHAR FROM TEST_CHAR;
D_CHAR
-------------------------------------------------------------
Typ=96 Len=10: 61,62,63,20,20,20,20,20,20,20
SQL> SELECT DUMP(VARCHAR_COL, 16) D_VARCHAR2 FROM TEST_CHAR;
D_VARCHAR2
-------------------------------------------------------------
Typ=1 Len=3: 31,32,33
SQL> SELECT DUMP(LONG_COL, 16) D_VARCHAR2 FROM TEST_CHAR;
SELECT DUMP(LONG_COL, 16) D_VARCHAR2 FROM TEST_CHAR
*
ERROR 位于第 1 行:
ORA-00997: 非法使用 LONG 数据类型
由于 DUMP 不支持 LONG 类型,因此我们使用了 alter system dump block 的方式,通过比较两种方式得到的结果,发现 DUMP()函数
不但方便,结果清晰,而且指出了进行 DUMP 的数据类型,在以后的例子中,除非必要的情况,否则都会采用 DUMP()函数的方式进行
说明。
下面看一下插入中文的情况,首先看一下数据库的字符集
SQL> select name, value$ from sys.props$ where name like '%CHARACTERSET%';
NAME VALUE$
------------------------------ ------------------------------
NLS_CHARACTERSET ZHS16GBK
NLS_NCHAR_CHARACTERSET AL16UTF16
SQL> insert into test_char values ('定长', '变长', null);
已创建 1 行。
SQL> SELECT DUMP(CHAR_COL, 16) D_CHAR FROM TEST_CHAR;
D_CHAR
----------------------------------------------------------------
Typ=96 Len=10: 61,62,63,20,20,20,20,20,20,20
Typ=96 Len=10: b6,a8,b3,a4,20,20,20,20,20,20
SQL> SELECT DUMP(VARCHAR_COL, 16) D_VARCHAR2 FROM TEST_CHAR;
D_VARCHAR2
----------------------------------------------------------------
Typ=1 Len=3: 31,32,33
Typ=1 Len=4: b1,e4,b3,a4
根据 dump 结果,可以清楚的看出,普通英文字符和标点用一个字节表示,而中文字符或中文标点需要两个字节来表示。
下面,对比一下 nchar 和 nvarchar2 与 char、varchar2 类型有什么不同。
SQL> create table test_nchar (nchar_col nchar(10), nvarchar_col nvarchar2(10));
表已创建。
SQL> insert into test_nchar values ('nchar 定长', 'nvarchar 变长');
已创建 1 行。
从这里已经可以看出一些不同了,如果按照刚才中文的计算方法,'nvarchar 变长'的长度是 8+2*2=12 已经超过了数据类型定义的大小,
可是为什么插入成功了?
还是 dump 一下看看结果吧。
SQL> select dump(nchar_col, 16) from test_nchar;
DUMP(NCHAR_COL,16)
--------------------------------------------------------------
Typ=96 Len=20: 0,6e,0,63,0,68,0,61,0,72,5b,9a,95,7f,0,20,0,20,0,20
SQL> select dump(nvarchar_col, 16) from test_nchar;
DUMP(NVARCHAR_COL,16)
--------------------------------------------------------------
Typ=1 Len=20: 0,6e,0,76,0,61,0,72,0,63,0,68,0,61,0,72,53,d8,95,7f
这下就明白了,虽然仍然是采用 ascii 码存储,但是 nchar 使用的 AL16UTF16 字符集,编码长度变为 2 个字节。这样中文使用两个字节,
对于可以用一个字节就表示的英文字符,采用了高位补 0 的方式凑足 2 位,这样,对于采用 AL16UTF16 字符集的 nchar 类型,无论中文
还是英文都用 2 位字符表示。因此'nvarchar 变长'的长度是 10,并没有超过数据类型的限制。
Oracle 基本数据类型存储格式浅析(二)——数字类型
这篇文章主要描述 NUMBER 类型的数据和如何在数据库中存储的。
Oracle的NUMBER类型最多由三个部分构成,这三个部分分别是最高位表示位、数据部分、符号位。其中负数包含符号位,正数不
会包括符号位。另外,数值 0 比较特殊,它只包含一个数值最高位表示位 80,没有数据部分。
正数的最高位表示位大于 80,负数的最高位表示位小于 80。其中一个正数的最高位是个位的话,则最高位表示位为 C1,百位、万位
依次为 C2、C3,百分位、万分为依次为 C0、BF。一个负数的最高位为个位的话,最高位表示位为 3E,百位、万位依次为 3D、3C,百
分位、万分位依次为 3F、40。
数据部分每一位都表示 2 位数。这个两位数可能是从 0 到 99,如果是数据本身是正数,则分别用二进制的 1 到 64 表示,如果数据本
身是负数,则使用二进制 65 到 2 表示。
符号位用 66 表示。
上面的这些是我通过 DUMP 结果总结出来的,对于上面提到的这些关系常数,Oracle 之所以这样选择是有道理的,我们后面根据例
子也可以推导出来,而且会进一步说明为什么会采用这种方式表示。这里列出的意思是使大家先对 NUMBER 类型数据有一个大概的了解。
下面我们通过一个例子详细说明:
SQL> CREATE TABLE TEST_NUMBER (NUMBER_COL NUMBER);
表已创建。
SQL> INSERT INTO TEST_NUMBER VALUES (0);
已创建 1 行。
SQL> INSERT INTO TEST_NUMBER VALUES (1);
已创建 1 行。
SQL> INSERT INTO TEST_NUMBER VALUES (2);
已创建 1 行。
SQL> INSERT INTO TEST_NUMBER VALUES (25);
已创建 1 行。
SQL> INSERT INTO TEST_NUMBER VALUES (123);
已创建 1 行。
SQL> INSERT INTO TEST_NUMBER VALUES (4100);
已创建 1 行。
SQL> INSERT INTO TEST_NUMBER VALUES (132004078);
已创建 1 行。
SQL> INSERT INTO TEST_NUMBER VALUES (2.01);
已创建 1 行。
SQL> INSERT INTO TEST_NUMBER VALUES (0.3);
已创建 1 行。
SQL> INSERT INTO TEST_NUMBER VALUES (0.00000125);
已创建 1 行。
SQL> INSERT INTO TEST_NUMBER VALUES (115.200003);
已创建 1 行。
SQL> INSERT INTO TEST_NUMBER VALUES (-1);
已创建 1 行。
SQL> INSERT INTO TEST_NUMBER VALUES (-5);
已创建 1 行。
SQL> INSERT INTO TEST_NUMBER VALUES (-20032);
已创建 1 行。
SQL> INSERT INTO TEST_NUMBER VALUES (-234.432);
已创建 1 行。
SQL> COMMIT;
提交完成。
SQL> COL D_NUMBER FORMAT A50
SQL> SELECT NUMBER_COL, DUMP(NUMBER_COL, 16) D_NUMBER FROM TEST_NUMBER;
NUMBER_COL D_NUMBER
---------- --------------------------------------------------
0 Typ=2 Len=1: 80
1 Typ=2 Len=2: c1,2
2 Typ=2 Len=2: c1,3
25 Typ=2 Len=2: c1,1a
123 Typ=2 Len=3: c2,2,18
4100 Typ=2 Len=2: c2,2a
132004078 Typ=2 Len=6: c5,2,21,1,29,4f
2.01 Typ=2 Len=3: c1,3,2
.3 Typ=2 Len=2: c0,1f
.00000125 Typ=2 Len=3: be,2,1a
115.200003 Typ=2 Len=6: c2,2,10,15,1,4
-1 Typ=2 Len=3: 3e,64,66
-5 Typ=2 Len=3: 3e,60,66
-20032 Typ=2 Len=5: 3c,63,65,45,66
-234.432 Typ=2 Len=6: 3d,63,43,3a,51,66
已选择 15 行。
下面根据例子得到的结果,对每行进行说明。首先说明两点基本的。DUMP 函数返回的 TYPE=2 表示 DUMP 的数据类型是 NUMBER,
LENGTH=N 表示数值在数据库中存储的长度是 N。
1.DUMP(0)的结果是 0x80,在前面已经提到,0 只有高位表示位,没有数据位。由于 0 的特殊,既不属于正数,也不属于负数,因此使
用高位表示位用 80 表示就足够了,不会和其它数据冲突,Oracle 出于节省空间的考虑将后面数据部分省掉了。但是为什么 Oracle 选择
0x80 表示 0 呢?我们知道正数和负数互为相反数,每个正数都有一个对应的负数。因此如果我们要使用编码表示数值,则表示正数和负
数的编码应该各占一半,这样才能保证使 Oracle 表示数据范围是合理的。而 0x80 的二进制编码是 1000 0000,正好是一个字节编码最
大值的一半,因此,Oracle 选择 0x80 来表示 0,是十分有道理的。
2.DUMP(1)的结果是 0xc102,0xc1 表示了最高位个位,0x2 表示数值是 1。首先,Oracle 为什么用 C1 表示个位呢?其实,道理和刚才
的差不多。采用科学计数法,任何一个实数 S 都可以描述为 A.B×10n,A 表示整数部分,B 表示小数部分,而 N 表示 10 的指数部分。当
S 大于 1 时,N 大于等于 0,S 小于 1 时,N 小于 0。也就是说,采用指数的方式表示,N 大于 0 和 N 小于 0 的情况各占一半左右时,
Oracle 所表示的范围最广。因此,Oracle 选择了 C1 表示个位是最高位的情况。
SQL> SELECT TO_CHAR(ROUND(TO_NUMBER('81', 'XXX') + (TO_NUMBER('FF', 'XXX') - TO_NUMBER('81', 'XXX') + 1)/2), 'XX')
FROM DUAL;
TO_
---
C1
为什么ORACLE使用0x2表示1,而不直接使用 0x1 表示 1 呢?Oracle 每个字节表示 2 位数,因此对于这个 2 位数,出现的可能是
0~99 共 100 种可能,问题出在 0 这里。Oracle 底层是用 C 语言实现的,我们知道二进制 0 在 C 语言中用作字符串终结符,Oracle 为
了避免这个问题,因此使用了 0x1 表示 0,并依次类推,使用 0x64 表示 99。
剩余26页未读,继续阅读
yifonger
- 粉丝: 0
- 资源: 1
上传资源 快速赚钱
- 我的内容管理 收起
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
会员权益专享
最新资源
- ExcelVBA中的Range和Cells用法说明.pdf
- 基于单片机的电梯控制模型设计.doc
- 主成分分析和因子分析.pptx
- 共享笔记服务系统论文.doc
- 基于数据治理体系的数据中台实践分享.pptx
- 变压器的铭牌和额定值.pptx
- 计算机网络课程设计报告--用winsock设计Ping应用程序.doc
- 高电压技术课件:第03章 液体和固体介质的电气特性.pdf
- Oracle商务智能精华介绍.pptx
- 基于单片机的输液滴速控制系统设计文档.doc
- dw考试题 5套.pdf
- 学生档案管理系统详细设计说明书.doc
- 操作系统PPT课件.pptx
- 智慧路边停车管理系统方案.pptx
- 【企业内控系列】企业内部控制之人力资源管理控制(17页).doc
- 温度传感器分类与特点.pptx
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论0