select id,name,rowid,
dbms_rowid.ROWID_RELATIVE_FNO(rowid) file_no,
dbms_rowid.ROWID_BLOCK_NUMBER(rowid) block_no,
dbms_rowid.ROWID_ROW_NUMBER(rowid) row_no from test01 order by id ;
ID NA ROWID FILE_NO BLOCK_NO ROW_NO
---------- -- ------------------ ---------- ---------- ----------
1 ab AAAVsvAAEAAAAkDAAA 4 2307 0
2 ab AAAVsvAAEAAAAkDAAB 4 2307 1
3 ab AAAVsvAAEAAAAkDAAC 4 2307 2
4 ab AAAVsvAAEAAAAkEAAA 4 2308 0
HEADER_FILE HEADER_BLOCK
----------- ------------
4 2306
BBED> info
File# Name Size(blks)
----- ---- ----------
4 /oradata/orcl/users01.dbf 7360
BBED> set dba 4,2307
DBA 0x01000903 (16779523 4,2307)
BBED> map
File: /oradata/orcl/users01.dbf (4)
Block: 2307 Dba:0x01000903
------------------------------------------------------------
KTB Data Block (Table/Cluster)
struct kcbh, 20 bytes @0
struct ktbbh, 72 bytes @20
struct kdbh, 14 bytes @100
struct kdbt[1], 4 bytes @114
sb2 kdbr[3] @118 -- row directory
ub1 freespace[2028] @124 --预留和未插满的空间
ub1 rowdata[6036] @2152 --业务数据占用6036字节 ,每行2013字节
ub4 tailchk @8188
预留空间:元数据0-123、8188-8191(块尾-4字节),同时预留 pcrtfree 10%给变长字段
总可以使用的空间= 8192-4-124=8064 一个块只能存放8064个字节
SQL> select length(id),length(name),length(other) from test01;
LENGTH(ID) LENGTH(NAME) LENGTH(OTHER)
---------- ------------ -------------
1 2 2000
1 2 2000
1 2 2000
--每一行2003,和上面的2013对不上,下面查原因
BBED> p kdbr --print kdbr内容
sb2 kdbr[0] @118 6076 6076-8188=2112个字节,比下面多100.下面解释
sb2 kdbr[1] @120 4064 4064-6076=2013个字节
sb2 kdbr[2] @122 2052 2052-4064=2013个字节
BBED> p *kdbr[0] --查看kdbr[0]内容
rowdata[4024]
-------------
ub1 rowdata[4024] @6176 0x2c
从这里看它的偏移量是 6176-8188=2013 (比上面算出来的6076多100,原因是里面还有些行元数据和标记位)
BBED> p *kdbr[1]
rowdata[2012]
-------------
ub1 rowdata[2012] @4164 0x2c 4164-6176=2013
BBED> p *kdbr[2]
rowdata[0]
----------
ub1 rowdata[0] @2152 0x2c 2152-4164=2013
BBED> x /rncc -- x /r 打印, n是number,c是字符
rowdata[0] @2152
----------
flag@2152: 0x2c (KDRHFL, KDRHFF, KDRHFH) --行元数据:row piece的标记
--KDRHF L: F-laster row piece的标记
F: F-first row piece的标记
H: H-header 横头
lock@2153: 0x01 --ITL LOCK BYTE
cols@2154: 3 --列数描述
col 0[2] @2155: 3 --2158-2155=3字节
col 1[2] @2158: ad
col 2[2000] @2161: other...col
update test01 set name='AAAAAAA' where id=1;
commit;
---把name a_1 修改成AAAAAAA后,数据库并未发生行迁移
ID NAME ROWID FILE_NO BLOCK_NO ROW_NO
---------- ---------- ------------------ ---------- ---------- ----------
1 AAAAAAA AAAV/UAAEAAAiIlAAA 4 139813 0
2 a_2 AAAV/UAAEAAAiIlAAB 4 139813 1
3 a_3 AAAV/UAAEAAAiIlAAC 4 139813 2
---修改前
BBED> p kdbr
sb2 kdbr[0] @118 6075
sb2 kdbr[1] @120 4062
sb2 kdbr[2] @122 2049
--修改后:
BBED> p kdbr
sb2 kdbr[0] @118 32 实际偏移量需要+100
sb2 kdbr[1] @120 4062
sb2 kdbr[2] @122 2049
BBED> p kdbr
sb2 kdbr[0] @118 6075
sb2 kdbr[1] @120 4062
sb2 kdbr[2] @122 2049
------模拟行迁移
drop table test01;
create table test01 (
id number,name varchar2(2000),
address varchar2(2000),
other_col char(2000));
begin
for i in 1..3 loop
insert into test01 values(i,i||'_a','ddd','other_col...');
end loop;
commit;
end;
/
SQL> select EXTENT_ID,file_id,block_id,blocks from dba_extents where segment_name='TEST01';
EXTENT_ID FILE_ID BLOCK_ID BLOCKS
---------- ---------- ---------- ----------
0 4 2312 8
SQL>
set linesize 1000
col address for a30
select id,rowid,
dbms_rowid.ROWID_RELATIVE_FNO(rowid) file_no,
dbms_rowid.ROWID_BLOCK_NUMBER(rowid) block_no,
dbms_rowid.ROWID_ROW_NUMBER(rowid) row_no from test01 order by id ;
ID NAME ADDRESS ROWID FILE_NO BLOCK_NO ROW_NO
---------- -------------------- ------------------------------ ------------------ ---------- ---------- ----------
1 1_a ddd AAAVswAAEAAAAkLAAA 4 2315 0
2 2_a ddd AAAVswAAEAAAAkLAAB 4 2315 1
3 3_a ddd AAAVswAAEAAAAkLAAC 4 2315 2
alter system flush buffer_cache;
alter system dump datafile 4 block 2315;
select * from v$diag_info;
--dump 文件
--第一行:
block_row_dump:
tab 0, row 0, @0x17b7 --ofset 6071
tl: 2017 fb: --H-FL-- lb: 0x1 cc: 4 --t1 -长度--占用2017
col 0: [ 2] c1 02
col 1: [ 3] 31 5f 61
col 2: [ 3] 64 64 64
col 3: [2000]
6f 74 68 65 72 5f 63 6f 6c 2e 2e 2e 20 20 20 20 20 20 20 20 20 20 20 20 20
--第二行:
tab 0, row 1, @0xfd6 --offset 4054
tl: 2017 fb: --H-FL-- lb: 0x1 cc: 4
col 0: [ 2] c1 03
col 1: [ 3] 32 5f 61
col 2: [ 3] 64 64 64
col 3: [2000]
6f 74 68 65 72 5f 63 6f 6c 2e 2e 2e 20 20 20 20 20 20 20 20 20 20 20 20 20
--第三行:
tab 0, row 2, @0x7f5 --offset 2037
tl: 2017 fb: --H-FL-- lb: 0x1 cc: 4
col 0: [ 2] c1 04
col 1: [ 3] 33 5f 61
col 2: [ 3] 64 64 64
col 3: [2000]
6f 74 68 65 72 5f 63 6f 6c 2e 2e 2e 20 20 20 20 20 20 20 20 20 20 20 20 20
从block dump看到每条记录的长度是2017(2017计算方法:3 + col_leng+标记字段
在block内的偏移量分别为:
2037
4054
6071
SQL> select 2017*3 from dual;
2017*3
----------
6051
一个block 8192,可容纳的长度是8192-124-4=8064 (4是tail,124是block header和ITL )
SQL> select 8064-3*2017 from dual;
8064-3*2017
-----------
2013
--超了剩余的2013空间了 ,会发生行迁移
update test01
set name=lpad('a',2000,'a'), --有原来的3个变成2000,增加1997
address=lpad('d',1000,'d') --有原来的3个变成1000,增加997
where id=1;
commit;
alter system flush buffer_cache;
--dump block
block_row_dump:
tab 0, row 0, @0x17b7
tl: 9 fb: --H----- lb: 0x2 cc: 0
nrid: 0x0100090c.0 -rdba next rowid,发生了行迁移 迁移到4,2316
tab 0, row 1, @0xfd6
tl: 2017 fb: --H-FL-- lb: 0x0 cc: 4
col 0: [ 2] c1 03
col 1: [ 3] 32 5f 61
col 2: [ 3] 64 64 64
--rdba转换成 file#,block#
select dbms_utility.data_block_address_file(to_number('100090c','xxxxxxx')) file#,
dbms_utility.data_block_address_block(to_number('100090c','xxxxxxx')) block#
from dual;
FILE# BLOCK#
---------- ----------
4 2316
较多的行迁移会导致性能下降,比如500row 放在一个block,都发生了行迁移,本来一个io 4ms解决,最后变成了500*4ms=2000ms 。
可能引起行迁移的操作:
--大量数据的更新
--加字段,带默认值
--模拟大量行迁移
drop table t10;
create table t10
( id number,
info1 varchar2(200),
info2 varchar2(200),
info3 varchar2(200),
info4 varchar2(200));
begin
for i in 1..20000 loop
insert into t10(id) values(i);
end loop;
commit;
end;
/
select id,
dbms_rowid.ROWID_RELATIVE_FNO(rowid) file_no,
dbms_rowid.ROWID_BLOCK_NUMBER(rowid) block_no,
dbms_rowid.ROWID_ROW_NUMBER(rowid) row_no from t10
where id <=10 order by 2,3,4,id;
ID FILE_NO BLOCK_NO ROW_NO
---------- ---------- ---------- ----------
1 4 2323 0
2 4 2323 1
3 4 2323 2
4 4 2323 3
5 4 2323 4
6 4 2323 5
7 4 2323 6
8 4 2323 7
9 4 2323 8
10 4 2323 9
10 rows selected.
select * from (select id,
dbms_rowid.ROWID_RELATIVE_FNO(rowid) file_no,
dbms_rowid.ROWID_BLOCK_NUMBER(rowid) block_no,
dbms_rowid.ROWID_ROW_NUMBER(rowid) row_no from t10)
where file_no=4 and block_no=2 order by 2,3,4,id;
660 rows selected. --可以看到一个block存放了660行
dump block 4,2323
avsp=0x32a --剩余空间,十进制是810 (avalible space)
tosp=0x32a
update t10 set info1='info1';
commit;
update t10 set info1='info2';
commit;
update t10 set info1='info3';
commit
update t10 set info1='info4';
commit;
查看是否行迁移:
@?/rdbms/admin/utlchain.sql
analyze table scott.t10 list chained rows into chained_rows;
select * from chained_rows;「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




