从行迁移想到的 [转帖]_MySQL, Oracle及数据库讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  MySQL, Oracle及数据库讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 3500 | 回复: 0   主题: 从行迁移想到的 [转帖]        下一篇 
wayne
注册用户
等级:中校
经验:1690
发帖:221
精华:0
注册:2011-7-21
状态:离线
发送短消息息给wayne 加好友    发送短消息息给wayne 发消息
发表于: IP:您无权察看 2011-8-16 16:55:45 | [全部帖] [楼主帖] 楼主

前两天研究了一下行迁移和行链接的物理结构。今天突然想到一个问题。

本文是根据行迁移和行链接一文引申而出,有些地方描述比较简单,详细的叙述可以参阅:

行迁移和行链接的物理存储:http://blog.itpub.net/post/468/19085

Oracle的行迁移本身是为了尽量避免行链接的发生,当发生行迁移时,Oracle会把数据挪到其他的block中,并在当前的block存放ROWID信息指向新的位置。这样Oracle可以保证记录本身的ROWID不变,因此对索引和其他应用程序来说,行迁移是透明的。当通过ROWID访问到原始地址时,Oracle根据原始地址保存的ROWID信息,找到新的位置从而访问到数据。

因此,我有一个疑问,如果记录本身的长度大于6个字节,也就是ROWID存储所需的空间,则这种方法不会有任何问题。但如果记录本身的长度小于6,当block空间存储满之后,如果发生了行迁移,Oracle如何存放这6个字节的ROWID信息呢。

于是,我猜想,Oracle不会将block完全装满,即使给出的PCTFREE参数等于0,Oracle也必须为行迁移时存放ROWID信息预留空间。

SQL> show parameter db_block_size
NAME                                 TYPE        VALUE
------------------------------------ ----------- -------------
db_block_size                        integer     8192
SQL> create table test (id varchar2(1)) pctfree 0 tablespace test;


表已创建。

SQL> insert into test select '1' from dba_objects;


已创建6270行。

SQL> commit;


提交完成。

SQL> select substr(rowid, 1, 15), count(*) from test group by substr(rowid, 1, 15);
SUBSTR(ROWID,1,15)               COUNT(*)
------------------------------ ----------
AAACHTAAHAAAAAK                       734
AAACHTAAHAAAAAL                       734
AAACHTAAHAAAAAM                       734
AAACHTAAHAAAAAN                       734
AAACHTAAHAAAAAO                       734
AAACHTAAHAAAAAP                       734
AAACHTAAHAAAAAQ                       734
AAACHTAAHAAAAAR                       734
AAACHTAAHAAAAAS                       398


已选择9行。

SQL> analyze table test compute statistics;


表已分析。

SQL> select avg_row_len from user_tables where table_name = 'TEST';
AVG_ROW_LEN
-----------
5


BLOCK的大小是8192。而每条记录的平均长度只有5(记录头3,长度1,数据1),加上记录的位置2个字节。每条记录约占用7字节。8192减去BLOCK HEAD(110左右)还剩8000左右,PCTFREE设置为0,至少应该可以存放1000条以上的记录,但是实际只存放了734条。剩余的空间就是为行迁移存储ROWID预留的空间。

SQL> select 8192 - 7 * 734 - 110 from dual;
8192-7*734-110
--------------
2944
SQL> select 2944/734 from dual;
2944/734
----------
4.01089918


可见Oracle为每条记录预留了4字节的空间。如果发生了行迁移,4字节加上长度和数据共6字节刚好够存储ROWID信息(记录头和记录的位置信息不变)。

SQL> alter table test modify (id varchar2(100));


表已更改。

SQL> update test set id = lpad('5', 100, '5') where rowid = 'AAACHTAAHAAAAAKAAB';


已更新 1 行。

SQL> commit;


提交完成。

SQL> alter system dump datafile 7 block 10;


系统已更改。

Dump文件:

Start dump data blocks tsn: 7 file#: 7 minblk 10 maxblk 10
buffer tsn: 7 rdba: 0x01c0000a (7/10)
scn: 0x0000.015ee903 seq: 0x01 flg: 0x06 tail: 0xe9030601
frmt: 0x02 chkval: 0xc7df type: 0x06=trans data
Block header dump:  0x01c0000a
.
.
.
block_row_dump:
tab 0, row 0, @0x1aa5
tl: 5 fb: --H-FL-- lb: 0x0  cc: 1
col  0: [ 1]  31
tab 0, row 1, @0x1141
tl: 9 fb: --H----- lb: 0x2  cc: 0
nrid:  0x01c00012.18e
tab 0, row 2, @0x1aaf
tl: 5 fb: --H-FL-- lb: 0x0  cc: 1
col  0: [ 1]  31
.
.
.
end_of_block_dump
End dump data blocks tsn: 7 file#: 7 minblk 10 maxblk 10


根据Dump文件,更新一条记录后就发生了行迁移,虽然此时Block中有足够的空间存放这100字节的数据。

SQL> update test set id = lpad('5', 100, '5');


已更新6270行。

SQL> commit;


提交完成。

SQL> select substr(rowid, 1, 15), count(*) from test group by substr(rowid, 1, 15);
SUBSTR(ROWID,1,15)               COUNT(*)
------------------------------ ----------
AAACHTAAHAAAAAK                       734
AAACHTAAHAAAAAL                       734
AAACHTAAHAAAAAM                       734
AAACHTAAHAAAAAN                       734
AAACHTAAHAAAAAO                       734
AAACHTAAHAAAAAP                       734
AAACHTAAHAAAAAQ                       734
AAACHTAAHAAAAAR                       734
AAACHTAAHAAAAAS                       398


已选择9行。

SQL> alter system dump datafile 7 block 10;


系统已更改。

SQL> analyze table test compute statistics;


表已分析。

SQL> analyze table test compute statistics;


表已分析。

SQL> select chain_cnt from user_tables where table_name = 'TEST';
CHAIN_CNT
----------
6270


Dump文件:

Start dump data blocks tsn: 7 file#: 7 minblk 10 maxblk 10
buffer tsn: 7 rdba: 0x01c0000a (7/10)
scn: 0x0000.015eea9c seq: 0x01 flg: 0x02 tail: 0xea9c0601
frmt: 0x02 chkval: 0x0000 type: 0x06=trans data
Block header dump:  0x01c0000a
.
.
.
block_row_dump:
tab 0, row 0, @0x1f97
tl: 9 fb: --H----- lb: 0x1  cc: 0
nrid:  0x01c00012.18f
tab 0, row 1, @0x1f8e
tl: 9 fb: --H----- lb: 0x1  cc: 0
nrid:  0x01c00012.18e
tab 0, row 2, @0x1f85
tl: 9 fb: --H----- lb: 0x1  cc: 0
nrid:  0x01c00012.190
tab 0, row 3, @0x1f7c
tl: 9 fb: --H----- lb: 0x1  cc: 0
nrid:  0x01c00012.191
tab 0, row 4, @0x1f73
tl: 9 fb: --H----- lb: 0x1  cc: 0
nrid:  0x01c00012.192
.
.
.
end_of_block_dump
End dump data blocks tsn: 7 file#: 7 minblk 10 maxblk 10


根据Dump和上面的分析后查询的结果,此时,表中所有记录都发生了行迁移。而正如预测中的一样,数据的ROWID并没有发生任何变化。

现在基本可以得出简单的结论,当记录的长度很小时(小于5),Oracle会自动为行迁移预留空间。




赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论