暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

oracle update 原理及行迁移

原创 四九年入国军 2024-11-18
112

 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进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论