Row Chaining &Row Migrating 定义
Row chaining:当数据第一次insert到一个块时就无法容纳,此时将发生row chaining,将放在多个块中由指针链接(用rowid链接)
ROW migrating:当一个块内数据 由于update更新操作导致,长度变大,原来的块放不下了,oracle将进行row migrating,将在原来的块中保存一个指针,指向新的datablock(但迁移行的rowid不变,通过rowid可以查到FILE#,BLOCK#)
与之有关的建立表时的 参数 PCTFREE,PCTUSED(ASSM(auto segment space mangagement)表空间 中pctused已经废弃,因为assm tablespace 不用 freelist管理空间,而用BITMAP,而PCTUSED主要作用就是告诉oracle什么时候 块要挂到freelist,没有 freelist了 所以pctused也废弃了,不过pctfree还有作用 还限制新行能否插入一个块中
)
PCTFREE:指定表内每个数据块中空间的百分比。PCTFREE 的值必须介于0 和99
之间。如果值为零,表示可以通过插入新行来填充整个块。缺省值为10。此值表示每
个块中保留着10% 的空间,用于更新现有的行以及插入新行,每个块最多可填充到
90%。
PCTUSED:指定为表内每个数据块维护的已用空间的最小百分比。如果一个块的已用
空间低于PCTUSED,则可在该块中插入行。PCTUSED 的值为介于0 和99 之间的整
数,缺省值为40。(segment management space manual时候 控制块是否在FREELIST上),pctfree加pctused要小于100
SQL> sho user 表已创建。 SQL> insert into t1 values('a','b','c','d');~~插入大数据 已创建 1 行。 NAME TYPE VALUE SQL> select pct_free from user_tables where table_name='T1'; PCT_FREE 可以看 到default pctfree为10,块大小为8192,还要留10%用于更新 ,块头信息+行数据区信息 应该<90%才能都放入这个块,而实验中每个字段为 2000字节,90%空间放不下数据行,将造成row chaining chained_rows表需要建立 Table created. 生成CHAINED_ROWS TABLE_NAME COUNT(*) SQL> ANALYZE TABLE T1 COMPUTE STATISTICS;~~~另外直接用analyze也可以分析统计出来 表已分析。 SQL> select num_rows,chain_cnt from dba_tables where table_name='T1' ; NUM_ROWS CHAIN_CNT SQL> create table t2 (a char(2000), b char(2000), c char(2000), d char(2000)) pc 表已创建。 SQL> select pct_free from user_tables where table_name='T2'; PCT_FREE SQL> insert into t2 values('a','b','c','d'); 已创建 1 行。 SQL> commit; 提交完成。 SQL> ANALYZE TABLE T2 COMPUTE STATISTICS; 表已分析。 SQL> select num_rows,chain_cnt from dba_tables where table_name='T2' ; NUM_ROWS CHAIN_CNT SQL> ANALYZE TABLE t2 LIST CHAINED ROWS; 表已分析。 SQL> SELECT table_name, count(*) from chained_rows GROUP BY table_name; TABLE_NAME COUNT(*) row chaining 的解决 SQL> alter table t1 pctfree 0; 表已更改。 用10046 跟踪move操作过程 会话已更改。 SQL> alter table t1 move; 表已更改。 WAIT #3: nam='direct path write' ela= 3 file number=4 first dba=2444 block cnt=13 obj#=0 tim=325785989 insert into seg$ (file#,block#,type#,ts#,blocks,extents,minexts,maxexts,extsize,extpct,user#,iniexts,lists,groups,cachehint,bitmapranges,hwmincr, spare1, scanhint) values ..................... SQL> alter session set events '10046 trace name context off'; 会话已更改。 SQL> ANALYZE TABLE T1 COMPUTE STATISTICS;~~~ 表已分析。 SQL> select num_rows,chain_cnt from dba_tables where table_name='T1' ; NUM_ROWS CHAIN_CNT 消除了row chaining~~~~另外MOVE 由于是重新insert这样造成rowid改变所以index的失效,move还会锁表 SQL> create table tm ( a int); 表已创建。 SQL> insert into tm values(1); 已创建 1 行。 SQL> commit; 提交完成。 SQL> create index tm_ind on tm(a); STATUS SQL> alter table TM MOVE; 表已更改。 SQL> select STATUS from user_indexes where index_name='TM_IND'; STATUS SQL> alter index tm_ind rebuild online ; 索引已更改。 SQL> 另外一种方式,row chaining出现的根本原因就是INSERT时候块太小,所以 要建立大块的表空间,下面是早期实验中此类方法的解决 Table created. SQL> insert into test2 values('a','aa','aaa','aaaa','aaaaa'); 1 row created. SEGMENT_NAME FILE_ID BLOCK_ID BLOCKS System altered. buffer tsn: 20 rdba: 0x02800022 (10/34) H-表示当前数据块是该行的第一个块(不一定包含该行的数据,如row migrate) SQL> ANALYZE TABLE TEST2 COMPUTE STATISTICS; Table analyzed. NUM_ROWS CHAIN_CNT SQL> @E:\oracle\product\10.1.0\Db_1\RDBMS\ADMIN\utlchain.sql; Table created. 生成CHAINED_ROWS SQL> ANALYZE TABLE test2 LIST CHAINED ROWS; 会放入 chained_rows Table analyzed. TABLE_NAME COUNT(*) NAME VALUE 查询系统中存在 row 链接的数量 HEAD_ROWID SQL> select rowid from test2; ROWID ~2个能得到当前 链接or migrate的数量 row链接 清除 move exp/imp不管用 ~因为本身这行太长 其他块一样放不下,所以 只能加db_block_size清除 System altered. NAME TYPE VALUE on 32-bit Windows NT, the granule size is 8 MB for SGAs larger than 128 MB 9I Enter value for par: ksmg_granule_size NAME VALUE ISDEFAULT ISMOD IS Tablespace created. SQL> alter table xh.test2 move tablespace test_16kb; Table altered. SQL> Table analyzed. SQL> SELECT table_name, count(*) from chained_rows GROUP BY table_name; no rows selected Table analyzed. SQL> select num_rows,chain_cnt from dba_tables where table_name='TEST2'; NUM_ROWS CHAIN_CNT Table truncated. SQL> ANALYZE TABLE test2 LIST CHAINED ROWS; Table analyzed. SQL> SELECT table_name, count(*) from chained_rows GROUP BY table_name; no rows selected~~~~~~~~~~~~~~~~~~~~~~~~消除了 ROW migrate 表已创建。 SQL> insert into migrate(a,b) values('a','a'); 已创建 1 行。 SQL> insert into migrate(a) values('b'); 已创建 1 行。 SQL> commit; 提交完成。 SQL> select segment_name,file_id,block_id,blocks from dba_extents where segment_ SEGMENT_NAME FILE_ID BLOCK_ID BLOCKS SQL> select file#,block# ,rowid from (select dbms_rowid.rowid_relative_fno(rowid FILE# BLOCK# ROWID SQL> SQL> ANALYZE TABLE migrate LIST CHAINED ROWS; 表已分析。 SQL> SELECT table_name, count(*) from chained_rows GROUP BY table_name; 未选定行 表已分析。 SQL> select num_rows,chain_cnt from dba_tables where table_name='MIGRATE' ; NUM_ROWS CHAIN_CNT 分析 现在有2行 没有row migrate SQL> alter system dump datafile 4 block 3685; 系统已更改。 H-FL的意思: 上边trace文件可以看出 2行都 存在该块中 SQL> ANALYZE TABLE migrate LIST CHAINED ROWS; 表已分析。 SQL> SELECT table_name, count(*) from chained_rows GROUP BY table_name; TABLE_NAME COUNT(*) SQL> ANALYZE TABLE MIGRATE COMPUTE STATISTICS; 表已分析。 SQL> select num_rows,chain_cnt from dba_tables where table_name='MIGRATE' ; NUM_ROWS CHAIN_CNT SQL> select file#,block# ,rowid from (select dbms_rowid.rowid_relative_fno(rowid FILE# BLOCK# ROWID SQL> alter system dump datafile 4 block 3685; 系统已更改。 col 1: [2000] -H-FL-- 可以看到 这行 头和尾都在一个块中 SQL> variable file# number; PL/SQL 过程已成功完成。 SQL> execute :blk#:=dbms_utility.data_block_address_block(to_number('1000e66',' PL/SQL 过程已成功完成。 SQL> print file# FILE# SQL> print blk# BLK# SQL> alter system dump datafile 4 block 3686; 系统已更改。 col 0: [2000] PL/SQL 过程已成功完成。 SQL> execute :blk#:=dbms_utility.data_block_address_block(to_number('1000e65',' PL/SQL 过程已成功完成。 SQL> print file# FILE# SQL> print blk# BLK# 可以看出正是 迁移前所在的位置 关于消除row migrate 有很多种方法 1.MOVE 方法 表已分析。 SQL> SELECT table_name, count(*) from chained_rows GROUP BY table_name; 未选定行 SQL> ANALYZE TABLE MIGRATE COMPUTE STATISTICS; 表已分析。 SQL> select num_rows,chain_cnt from dba_tables where table_name='MIGRATE' ; NUM_ROWS CHAIN_CNT 消除了 (注意move 会让index失效,而且 LOCK表) 2.EXP/IMP 方法 表已创建。 SQL> insert into migrate2(a,b) values('a','a'); 已创建 1 行。 SQL> insert into migrate2(a) values('b'); 已创建 1 行。 SQL> commit; 提交完成。 SQL> update migrate2 set b='b',c='b' where a='b'; 已更新 1 行。 SQL> commit; 提交完成。 SQL> ANALYZE TABLE migrate2 LIST CHAINED ROWS; 表已分析。 SQL> SELECT table_name, count(*) from chained_rows GROUP BY table_name; TABLE_NAME COUNT(*) SQL> ANALYZE TABLE MIGRATE2 COMPUTE STATISTICS; 表已分析。 SQL> select num_rows,chain_cnt from dba_tables where table_name='MIGRATE2' ; NUM_ROWS CHAIN_CNT C:\>mkdir e:\exp C:\>exp xh/a831115 file=e:\exp\migrate2.dmp tables=migrate2 Export: Release 10.2.0.1.0 - Production on 星期六 10月 24 23:58:38 2009 Copyright (c) 1982, 2005, Oracle. All rights reserved. 即将导出指定的表通过常规路径... SQL> truncate table migrate2; 表被截断。 Import: Release 10.2.0.1.0 - Production on 星期日 10月 25 00:05:16 2009 Copyright (c) 1982, 2005, Oracle. All rights reserved. 经由常规路径由 EXPORT:V10.02.01 创建的导出文件 SQL> ANALYZE TABLE MIGRATE2 COMPUTE STATISTICS; 表已分析。 SQL> select num_rows,chain_cnt from dba_tables where table_name='MIGRATE2' ; NUM_ROWS CHAIN_CNT SQL> truncate table chained_rows; 表被截断。 SQL> ANALYZE TABLE migrate LIST CHAINED ROWS; 表已分析。 SQL> SELECT table_name, count(*) from chained_rows GROUP BY table_name; 未选定行 SQL> 3.CTAS 方式 CREATE TABLE table_name_temp AS SELECT * FROM table_name WHERE rowid IN(SELECT head_rowid FROM chained_rows WHERE table_name = 'table_name'); 表已创建。 SQL> insert into migrate3(a,b) values('a','a'); 已创建 1 行。 SQL> insert into migrate3(a) values('b'); 已创建 1 行。 SQL> commit; 提交完成。 SQL> update migrate3 set b='b',c='b' where a='b'; 已更新 1 行。 SQL> commit; 提交完成。 SQL> ANALYZE TABLE migrate3 LIST CHAINED ROWS; 表已分析。 SQL> SELECT table_name, count(*) from chained_rows GROUP BY table_name; TABLE_NAME COUNT(*) SQL> ANALYZE TABLE MIGRATE3 COMPUTE STATISTICS; 表已分析。 SQL> select num_rows,chain_cnt from dba_tables where table_name='MIGRATE3' ; NUM_ROWS CHAIN_CNT SQL> create table migrate3_test as select * from migrate3 where rowid in (select 表已创建。 SQL> delete migrate3 where rowid in (select head_rowid from chained_rows where t 已删除 1 行。 SQL> commit; 提交完成。 SQL> insert into migrate3 select * from MIGRATE3_TEST; 已创建 1 行。 SQL> commit 提交完成。 表已删除。 SQL> ANALYZE TABLE MIGRATE3 COMPUTE STATISTICS; 表已分析。 SQL> select num_rows,chain_cnt from dba_tables where table_name='MIGRATE3' ; NUM_ROWS CHAIN_CNT SQL> TRUNCATE TABLE CHAINED_ROWS ; 表被截断。 SQL> ANALYZE TABLE migrate3 LIST CHAINED ROWS; 表已分析。 SQL> SELECT table_name, count(*) from chained_rows GROUP BY table_name; 未选定行 消除了 关于表压缩 oracle compress SQL> create table cm (a char(20),b char(20)); 表已创建。 1 declare PL/SQL 过程已成功完成。 SQL> SQL> select count(distinct a) from cm; COUNT(DISTINCTA) SQL> select count(distinct b) from cm; COUNT(DISTINCTB) SQL> SEGMENT_NA FILE_ID BLOCK_ID BLOCKS SQL> select file_id,block_id,blocks from dba_extents where segment_name='CM'; FILE_ID BLOCK_ID BLOCKS SQL> select distinct block# from (select dbms_rowid.rowid_relative_fno(rowid) f BLOCK# BLOCK# 已选择13行。 SQL> 表已更改。 SEGMENT_NA FILE_ID BLOCK_ID BLOCKS SQL> select file_id,block_id,blocks from dba_extents where segment_name='CM'; FILE_ID BLOCK_ID BLOCKS SQL> select distinct block# from (select dbms_rowid.rowid_relative_fno(rowid) f BLOCK# 已选择8行。 系统已更改。 data_block_dump,data header at 0x80c227c tab 1, row 0, @0x1f4e tab 1, row 714, @0x115c 关于compress与 row migrate 如果执行UPDATE 将造成row migrate 表变大. 表已分析。 SQL> select num_rows,chain_cnt from dba_tables where table_name='CM' ; NUM_ROWS CHAIN_CNT 已更新2000行。 SQL> commit; 提交完成。 SQL> analyze table cm compute statistics; 表已分析。 SQL> select num_rows,chain_cnt from dba_tables where table_name='CM' ; NUM_ROWS CHAIN_CNT 一个update操作产生大量row migrate 系统已更改。 tl: 9 fb: --H----- lb: 0x2 cc: 0 SEGMENT_NA FILE_ID BLOCK_ID BLOCKS
小结:总得来说PCTFREE 就是告诉ORACLE 什么时候把BLOCK从FREELIST拿走(自动段空间管理没有FREELIST)拿走后,当空闲空间=pctfree时候 将不允许插入新数据,然后随着使用即使以后的空闲空间>PCTFREE 块也不挂到FREELIST(使用空间<90%时),只有当已使用空间
由于是1OGR2 默认表空间都是ASSM 简单实验下pctfree对row chaining的影响
USER 为 "XH"
SQL>
SQL> create table t1 (a char(2000), b char(2000), c char(2000), d char(2000));建立一个表
SQL> show parameter block_size
------------------------------------ ----------- ------------------------------
db_block_size integer 8192
----------
10
SQL> ANALYZE TABLE t1 LIST CHAINED ROWS;oracle分析表 如果有row chaining or row migrate 那么将会放入chained_rows这个表
表已分析。
脚本 位置 :RDBMS\ADMIN\utlchain.sql;
create table CHAINED_ROWS (
owner_name varchar2(30),
table_name varchar2(30),
cluster_name varchar2(30),
partition_name varchar2(30),
subpartition_name varchar2(30),
head_rowid rowid,
analyze_timestamp date
);
SQL> SELECT table_name, count(*) from chained_rows GROUP BY table_name;
------------------------------ ----------
T1 1~~~~看到有一个row chaining
---------- ----------
1 1~~~~~~~~~~~~~~~~~~~~~~~~~
tfree 0;
----------
0
建立另外一个表 T2 PCTFREE设置为0 没有留update空间,行数据区+块头信息 可以使用块的100%空间
---------- ----------
1 0~~~~~~~~~~没有产生row chainging
------------------------------ ----------
T1 1~~~~~~~~~~没有表T2的信息
降低PCT FREE
看 到内部相当于 一个 ctas操作
SQL> alter session set events '10046 trace name context forever,level 12';
trace中 摘录内容:
WAIT #3: nam='direct path write' ela= 49 file number=4 first dba=2444 block cnt=13 obj#=0 tim=325786033
WAIT #3: nam='direct path write' ela= 2 file number=4 first dba=2458 block cnt=5 obj#=0 tim=325786070
WAIT #3: nam='direct path write' ela= 3 file number=4 first dba=2458 block cnt=5 obj#=0 tim=325786418
WAIT #3: nam='direct path write' ela= 59 file number=4 first dba=2458 block cnt=5 obj#=0 tim=325786474
看到大量的 直接路径插入 实验 表
更新数据字典操作
delete from seg$ where ts#=:1 and file#=:2 and block#=:3
---------- ----------
1 0
SQL> select STATUS from user_indexes where index_name='TM_IND';
--------
VALID~~~~~~~~~~~~INDEX 失效
--------
UNUSABLE
SQL> create table test2(a char(2000),b char(2000),c char(2000),d char(2000),e ch
ar(2000)) tablespace test;
commit;
SQL> select segment_name,file_id,block_id,blocks from dba_extents where segment_
name='TEST2' and wner='XH';
-------------------- ---------- ---------- ----------
TEST2 10 33 8
SQL> alter system dump datafile 10 block min 34 block max 42;
转储一下数据块的结构
block_row_dump:
tab 0, row 0, @0x69
tl: 7967 fb: -----LP- lb: 0x1 cc: 4(4列)
col 0: [1952]
........................
buffer tsn: 20 rdba: 0x02800023 (10/35)
tab 0, row 0, @0x1793
tl: 2061 fb: --H-F--N lb: 0x1 cc: 2(2列)
nrid: 0x02800022.0***** 用rowid连接
col 0: [2000]
~~~~~~~~~~~~~~~~~~~~~~~~~~6列分到2个block中
F-表示该行数据的第一个片断
L-表示改行的最后一个片断
FL-表示改行的数据都在该数据快中.
N-表示该行在当前这个数据块中的最后一列没有结束,其余的数据存放在由rowid指向的下一个数据块中 (next表示这一行连接到下一行)。
P-表示该行在当前这个数据块中的第一列是从别的块延续过来的。
PN-会出现在行chained的地方,如果一行的数据超过一个块时就会出现
计算下row migregate or row链接数量
SQL> select num_rows,chain_cnt from dba_tables where table_name='TEST2' ;
---------- ----------
1 1 ~~~~~~有一个行链接
create table CHAINED_ROWS (
owner_name varchar2(30),
table_name varchar2(30),
cluster_name varchar2(30),
partition_name varchar2(30),
subpartition_name varchar2(30),
head_rowid rowid,~~*************************
analyze_timestamp date
);
SQL> SELECT table_name, count(*) from chained_rows GROUP BY table_name;
------------------------------ ----------
TEST2 1
SQL> SELECT name, value FROM v$sysstat WHERE name = 'table fetch continued row'
2 ;
---------------------------------------------------------------- ----------
table fetch continued row 164
SQL> SELECT head_rowid from chained_rows;~
------------------
AAANORAAKAAAAAjAAA
------------------
AAANORAAKAAAAAjAAA
SQL> alter system set db_16k_cache_size=2m;
SQL> show parameter db_16
------------------------------------ ----------- ------------------------------
db_16k_cache_size big integer 8M ~~~~~granule
on 32-bit Windows, the granule size is 8 M for SGAs larger than 1 GB. 10G
受 _ksmg_granule_size控制
old 14: x.ksppinm like '%_&par%'
new 14: x.ksppinm like '%_ksmg_granule_size%'
ADJ
------------------------------ ------------------------- --------- ---------- --
---
KSPPDESC
--------------------------------------------------------------------------------
----------------------------------------------------
_ksmg_granule_size 4194304 TRUE FALSE FA
LSE
granule size in bytes
SQL> create tablespace test_16KB datafile 'd:\test_16KB.dbf' size 10m blocksize
16k;
SQL> ANALYZE TABLE test2 LIST CHAINED ROWS;
SQL> ANALYZE TABLE TEST2 COMPUTE STATISTICS;
---------- ----------
1 0****************************
SQL> truncate table chained_rows;
SQL> create table migrate (a char(2000), b char(2000),c char(2000));
name='MIGRATE' and wner='XH';
------------------------------ ---------- ---------- ----------
MIGRATE 4 3681 8
) file#,dbms_rowid.rowid_block_number(rowid) block# ,rowid from MIGRATE);
---------- ---------- ------------------
4 3685 AAANSQAAEAAAA5lAAA
4 3685 AAANSQAAEAAAA5lAAB
SQL> ANALYZE TABLE MIGRATE COMPUTE STATISTICS;
---------- ----------
2 0
data_block_dump,data header at 0x8062264
===============
tsiz: 0x1f98
hsiz: 0x16
pbl: 0x08062264
bdba: 0x01000e65
76543210
flag=--------
ntab=1
nrow=2
frre=-1
fsbo=0x16
fseo=0x819
avsp=0x803
tosp=0x803
0xe:pti[0] nrow=2 offs=0
0x12:pri[0] offs=0xfef
0x14:pri[1] offs=0x819
block_row_dump:
tab 0, row 0, @0xfef
tl: 4009 fb: --H-FL-- lb: 0x1 cc: 2 (第1行中2列)
col 0: [2000]
61 20 20 20 20 20 20 2~~~~~~~~~~~~~~~值A
col 1: [2000]
61 20 20 20 ~~~~~~~~~~~~~~~~~~~~~~~~值A
tl: 2006 fb: --H-FL-- lb: 0x1 cc: 1(第2行中2列)
col 0: [2000]
62 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
20 20 20 20 20 ~~~~~~~~~~~~~~~~~~~~~~~值B
H-表示当前数据块是该行的第一个块
FL-表示改行的数据都在该数据快中
------------------------------ ----------
MIGRATE 1
---------- ----------
2 1
) file#,dbms_rowid.rowid_block_number(rowid) block# ,rowid from MIGRATE);
---------- ---------- ------------------
4 3685 AAANSQAAEAAAA5lAAA
4 3685 AAANSQAAEAAAA5lAAB~~~rowid没变
flag=--------
ntab=1
nrow=2
frre=-1
fsbo=0x16
fseo=0x819
avsp=0x803
tosp=0xfd0
0xe:pti[0] nrow=2 offs=0
0x12:pri[0] offs=0xfef
0x14:pri[1] offs=0x819
block_row_dump:
tab 0, row 0, @0xfef
tl: 4009 fb: --H-FL-- lb: 0x0 cc: 2(2列)
col 0: [2000]
61 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
20 20 20 20 20
61 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
20 20 20 20 2
tl: 9 fb: --H----- lb: 0x2 cc: 0~~~~~~~(0列 原来的 数据迁移了)
nrid: 0x01000e66.0~~~指针指向迁移的block,ROWID不变,可以从H 看出来 表示当前数据块是该行的第一个块(不一定包含该行的数据,如row migrate)
end_of_block_dump
通过NRID 找到 迁移行所在的block
SQL> variable blk# number;
SQL> execute :file#:=dbms_utility.data_block_address_file(to_number('1000e66','x
xxxxxx'));
xxxxxxx'));
----------
4
----------
3686
flag=--------
ntab=1
nrow=1
frre=-1
fsbo=0x14
fseo=0x7fe
avsp=0x7ea
tosp=0x7ea
0xe:pti[0] nrow=1 offs=0
0x12:pri[0] offs=0x7fe
block_row_dump:
tab 0, row 0, @0x7fe
tl: 6018 fb: ----FL-- lb: 0x1 cc: 3(3列)
hrid: 0x01000e65.1*****这个HRID 也是一个指针 指向原来迁移的位置的块
62 20 20 20 ~~~~值B
col 1: [2000]
62 20 20 20~~~~值B
col 2: [2000]
62 20 20 20~~~~值B
通过hrid找到原来迁移前所在的block
SQL> variable blk# number;
SQL> variable file# number;
SQL> execute :file#:=dbms_utility.data_block_address_file(to_number('1000e65','x
xxxxxx'));
xxxxxxx'));
----------
4
----------
3685
SQL> ANALYZE TABLE migrate LIST CHAINED ROWS;
---------- ----------
2 0
SQL> create table migrate2 (a char(2000), b char(2000),c char(2000));
------------------------------ ----------
MIGRATE2 1
---------- ----------
2 1
连接到: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
已导出 ZHS16GBK 字符集和 AL16UTF16 NCHAR 字符集
. . 正在导出表 MIGRATE2导出了 2 行
成功终止导出, 没有出现警告。
C:\>imp xh/a831115 file=e:\exp\migrate2.dmp tables=migrate2 ignore=y
连接到: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
已经完成 ZHS16GBK 字符集和 AL16UTF16 NCHAR 字符集中的导入
. 正在将 XH 的对象导入到 XH
. 正在将 XH 的对象导入到 XH
. . 正在导入表 "MIGRATE2"导入了 2 行
成功终止导入, 没有出现警告。
---------- ----------
2 0
消除了
DELETE table_name WHERE rowid IN(SELECT head_rowidFROM chained_rowsWHERE table_name = 'table_name');
INSERT INTO table_name SELECT * FROM table_name_temp;DROP TABLE table_name_temp;
很简单ctas重新建立一个表(直接加载写入)
将迁移行 复制到 新表中
从原始表删除迁移行
将行从新表复制到原表中
SQL> create table migrate3 (a char(2000), b char(2000),c char(2000));
------------------------------ ----------
MIGRATE3 1
---------- ----------
2 1
head_rowid from chained_rows where table_name='MIGRATE3');
able_name='MIGRATE3');
2 ;
SQL> drop TABLE MIGRATE3_TEST;
---------- ----------
2 0
可以压缩数据块内重复的值,重复值存在符号表(块头),原来位置存一个指针指向符号表
SQL> ed
已写入 file afiedt.buf
2 begin
3 for i in 1..1000 loop
4 insert into cm values('a','b');
5 end loop;
6 for i in 1..1000 loop
7 insert into cm values('a'||i,'b'||i);
8 end loop;
9 commit;
10* end;
11 /
----------------
1001
----------------
1001
可以 看到这个表a,b列有1001个不同值
SQL> col segment_name format a10
SQL> select segment_name,file_id,block_id,blocks from dba_extents where segment
_name='CM';
---------- ---------- ---------- ----------
CM 4 2329 8
CM 4 2353 8
---------- ---------- ----------
4 2329 8
4 2353 8
ile#,dbms_rowid.rowid_block_number(rowid) block# ,rowid from CM);
----------
2333
2353
2354
2357
2358
2359
2332
2334
2335
2336
2355
----------
2356
2360
SQL> alter table xh.cm move compress;
SQL> select segment_name,file_id,block_id,blocks from dba_extents where segment
_name='CM';
---------- ---------- ---------- ----------
CM 4 2361 8
CM 4 2369 8
---------- ---------- ----------
4 2361 8
4 2369 8
ile#,dbms_rowid.rowid_block_number(rowid) block# ,rowid from CM);
----------
2364
2367
2368
2369
2371
2365
2366
2370
~~~~~~~~~~~~~~~~可以看到使用的 块减少了(13减少为8)
转储结构看下
SQL> alter system dump datafile 4 block 2364;
===============
tsiz: 0x1f80 (total data area size)
hsiz: 0x5bc (data header size=(14+ntabs*4 + nrows*2)
pbl: 0x080c227c (pointer to buffer holding the block)
bdba: 0x0100093c (block dba ,rdba)
76543210
flag=-0------(O表示 compress , n=pctfree hit (clusters),f=don't put on freelist, k=flushable cluster keys)
ntab=2 (表示块中含有2个表信息,有一个就是symbol table,cluster时候也>1)
nrow=716 (number of rows)~~~可以看到如果是正常表,这个块是存不了 这么多行应该在200ROW左右
frre=-1
fsbo=0x5bc (free space begin offset)
fseo=0x115c (free space end offset)
avsp=0x74 (available space in the block)
tosp=0x74(total available space when all transactions commit)
r0_9ir2=0x0
mec_kdbh9ir2=0x1
76543210
shcf_kdbh9ir2=----------
76543210
flag_9ir2=--R----C
fcls_9ir2[3]={ 0 32768 32768 }
0x1c:pti[0] nrow=1 offs=0 (symbol表里有一条记录(a,b)存compress后的值)
0x20:pti[1] nrow=715 offs=1 这个block中其余 715条是重复记录只存指向symbol的指针
0x24:pri[0] offs=0x1f53
0x26:pri[1] offs=0x1f4e
0x28:pri[2] offs=0x1f49
''''''''''''''''''''''''''''''
0x5ba:pri[715] offs=0x115c
block_row_dump:
tab 0, row 0, @0x1f53 (tab 0 就是符号表)
tl: 45 fb: --H-FL-- lb: 0x0 cc: 2
col 0: [20] 61 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 值 A
col 1: [20] 62 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 值 B
bindmp: 02 cb 02 dc 61 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 dc 62 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
tl: 5 fb: --H-FL-- lb: 0x0 cc: 2
col 0: [20] 61 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20~~~值A
col 1: [20] 62 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20~~~值B
bindmp: 2c 00 01 02 00 (02 表示compress 2个字段)
.................................
tl: 5 fb: --H-FL-- lb: 0x0 cc: 2
col 0: [20] 61 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
col 1: [20] 62 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
bindmp: 2c 00 01 02 00~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~指针指向符号表,存储的实际值,就是这样大量的指针指向符号表
SQL> analyze table cm compute statistics;
---------- ----------
2000 0
SQL> update cm set b='c';
---------- ----------
2000 844
SQL> alter system dump datafile 4 block 2364;
nrid: 0x01000944.0~~~~~~~~~~~~~~~~~~~~~~~~~~~~ROW migrate 指向迁移到的block
bindmp: 20 02 00 01 00 09 44 00 00
tab 1, row 3, @0x1ee5
tl: 9 fb: --H----- lb: 0x2 cc: 0
nrid: 0x01000944.1
bindmp: 20 02 00 01 00 09 44 00 01
tab 1, row 4, @0x1edc
tl: 9 fb: --H----- lb: 0x2 cc: 0
nrid: 0x01000944.2
SQL> col segment_name format a10
SQL> select segment_name,file_id,block_id,blocks from dba_extents where segment_
name='CM';
---------- ---------- ---------- ----------
CM 4 2361 8
CM 4 2369 8
CM 4 2409 8~~~~~~~~~~~~可以看到表变大了(原来是2个区,现在3个区)
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/12020513/viewspace-611339/ ,如需转载,请注明出处,否则将追究法律责任。