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
小结:总得来说PCTFREE 就是告诉ORACLE 什么时候把BLOCK从FREELIST拿走(自动段空间管理没有FREELIST)拿走后,当空闲空间=pctfree时候 将不允许插入新数据,然后随着使用即使以后的空闲空间>PCTFREE 块也不挂到FREELIST(使用空间<90%时),只有当已使用空间
由于是1OGR2 默认表空间都是ASSM 简单实验下pctfree对row chaining的影响
SQL> sho user
USER 为 "XH"
SQL>
SQL> create table t1 (a char(2000), b char(2000), c char(2000), d char(2000));建立一个表
表已创建。
SQL> insert into t1 values('a','b','c','d');~~插入大数据
已创建 1 行。
SQL> show parameter block_size
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
db_block_size integer 8192
SQL> select pct_free from user_tables where table_name='T1';
PCT_FREE
----------
10
可以看 到default pctfree为10,块大小为8192,还要留10%用于更新 ,块头信息+行数据区信息 应该<90%才能都放入这个块,而实验中每个字段为 2000字节,90%空间放不下数据行,将造成row chaining
SQL> ANALYZE TABLE t1 LIST CHAINED ROWS;oracle分析表 如果有row chaining or row migrate 那么将会放入chained_rows这个表
表已分析。
chained_rows表需要建立
脚本 位置 :RDBMS\ADMIN\utlchain.sql;
Table created. 生成CHAINED_ROWS
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;
TABLE_NAME COUNT(*)
------------------------------ ----------
T1 1~~~~看到有一个row chaining
SQL> ANALYZE TABLE T1 COMPUTE STATISTICS;~~~另外直接用analyze也可以分析统计出来
表已分析。
SQL> select num_rows,chain_cnt from dba_tables where table_name='T1' ;
NUM_ROWS CHAIN_CNT
---------- ----------
1 1~~~~~~~~~~~~~~~~~~~~~~~~~
SQL> create table t2 (a char(2000), b char(2000), c char(2000), d char(2000)) pc
tfree 0;
表已创建。
SQL> select pct_free from user_tables where table_name='T2';
PCT_FREE
----------
0
建立另外一个表 T2 PCTFREE设置为0 没有留update空间,行数据区+块头信息 可以使用块的100%空间
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
---------- ----------
1 0~~~~~~~~~~没有产生row chainging
SQL> ANALYZE TABLE t2 LIST CHAINED ROWS;
表已分析。
SQL> SELECT table_name, count(*) from chained_rows GROUP BY table_name;
TABLE_NAME COUNT(*)
------------------------------ ----------
T1 1~~~~~~~~~~没有表T2的信息
row chaining 的解决
降低PCT FREE
SQL> alter table t1 pctfree 0;
表已更改。
用10046 跟踪move操作过程
看 到内部相当于 一个 ctas操作
SQL> alter session set events '10046 trace name context forever,level 12';
会话已更改。
SQL> alter table t1 move;
表已更改。
trace中 摘录内容:
WAIT #3: nam='direct path write' ela= 3 file number=4 first dba=2444 block cnt=13 obj#=0 tim=325785989
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
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
---------- ----------
1 0
消除了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);
SQL> select STATUS from user_indexes where index_name='TM_IND';
STATUS
--------
VALID~~~~~~~~~~~~INDEX 失效
SQL> alter table TM MOVE;
表已更改。
SQL> select STATUS from user_indexes where index_name='TM_IND';
STATUS
--------
UNUSABLE
SQL> alter index tm_ind rebuild online ;
索引已更改。
SQL>
另外一种方式,row chaining出现的根本原因就是INSERT时候块太小,所以 要建立大块的表空间,下面是早期实验中此类方法的解决
SQL> create table test2(a char(2000),b char(2000),c char(2000),d char(2000),e ch
ar(2000)) tablespace test;
Table created.
SQL> insert into test2 values('a','aa','aaa','aaaa','aaaaa');
1 row created.
commit;
SQL> select segment_name,file_id,block_id,blocks from dba_extents where segment_
name='TEST2' and wner='XH';
SEGMENT_NAME FILE_ID BLOCK_ID BLOCKS
-------------------- ---------- ---------- ----------
TEST2 10 33 8
SQL> alter system dump datafile 10 block min 34 block max 42;
System altered.
转储一下数据块的结构
buffer tsn: 20 rdba: 0x02800022 (10/34)
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中
H-表示当前数据块是该行的第一个块(不一定包含该行的数据,如row migrate)
F-表示该行数据的第一个片断
L-表示改行的最后一个片断
FL-表示改行的数据都在该数据快中.
N-表示该行在当前这个数据块中的最后一列没有结束,其余的数据存放在由rowid指向的下一个数据块中 (next表示这一行连接到下一行)。
P-表示该行在当前这个数据块中的第一列是从别的块延续过来的。
PN-会出现在行chained的地方,如果一行的数据超过一个块时就会出现
SQL> ANALYZE TABLE TEST2 COMPUTE STATISTICS;
Table analyzed.
计算下row migregate or row链接数量
SQL> select num_rows,chain_cnt from dba_tables where table_name='TEST2' ;
NUM_ROWS CHAIN_CNT
---------- ----------
1 1 ~~~~~~有一个行链接
SQL> @E:\oracle\product\10.1.0\Db_1\RDBMS\ADMIN\utlchain.sql;
Table created. 生成CHAINED_ROWS
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> ANALYZE TABLE test2 LIST CHAINED ROWS; 会放入 chained_rows
Table analyzed.
SQL> SELECT table_name, count(*) from chained_rows GROUP BY table_name;
TABLE_NAME COUNT(*)
------------------------------ ----------
TEST2 1
SQL> SELECT name, value FROM v$sysstat WHERE name = 'table fetch continued row'
2 ;
NAME VALUE
---------------------------------------------------------------- ----------
table fetch continued row 164
查询系统中存在 row 链接的数量
SQL> SELECT head_rowid from chained_rows;~
HEAD_ROWID
------------------
AAANORAAKAAAAAjAAA
SQL> select rowid from test2;
ROWID
------------------
AAANORAAKAAAAAjAAA
~2个能得到当前 链接or migrate的数量
row链接 清除 move exp/imp不管用 ~因为本身这行太长 其他块一样放不下,所以 只能加db_block_size清除
SQL> alter system set db_16k_cache_size=2m;
System altered.
SQL> show parameter db_16
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
db_16k_cache_size big integer 8M ~~~~~granule
on 32-bit Windows NT, the granule size is 8 MB for SGAs larger than 128 MB 9I
on 32-bit Windows, the granule size is 8 M for SGAs larger than 1 GB. 10G
受 _ksmg_granule_size控制
Enter value for par: ksmg_granule_size
old 14: x.ksppinm like '%_&par%'
new 14: x.ksppinm like '%_ksmg_granule_size%'
NAME VALUE ISDEFAULT ISMOD IS
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;
Tablespace created.
SQL> alter table xh.test2 move tablespace test_16kb;
Table altered.
SQL>
SQL> ANALYZE TABLE test2 LIST CHAINED ROWS;
Table analyzed.
SQL> SELECT table_name, count(*) from chained_rows GROUP BY table_name;
no rows selected
SQL> ANALYZE TABLE TEST2 COMPUTE STATISTICS;
Table analyzed.
SQL> select num_rows,chain_cnt from dba_tables where table_name='TEST2';
NUM_ROWS CHAIN_CNT
---------- ----------
1 0****************************
SQL> truncate table chained_rows;
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> create table migrate (a char(2000), b char(2000),c char(2000));
表已创建。
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_
name='MIGRATE' and wner='XH';
SEGMENT_NAME FILE_ID BLOCK_ID BLOCKS
------------------------------ ---------- ---------- ----------
MIGRATE 4 3681 8
SQL> select file#,block# ,rowid from (select dbms_rowid.rowid_relative_fno(rowid
) file#,dbms_rowid.rowid_block_number(rowid) block# ,rowid from MIGRATE);
FILE# BLOCK# ROWID
---------- ---------- ------------------
4 3685 AAANSQAAEAAAA5lAAA
4 3685 AAANSQAAEAAAA5lAAB
SQL>
SQL> ANALYZE TABLE migrate LIST CHAINED ROWS;
表已分析。
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
---------- ----------
2 0
分析 现在有2行 没有row migrate
SQL> alter system dump datafile 4 block 3685;
系统已更改。
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的意思:
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(*)
------------------------------ ----------
MIGRATE 1
SQL> ANALYZE TABLE MIGRATE COMPUTE STATISTICS;
表已分析。
SQL> select num_rows,chain_cnt from dba_tables where table_name='MIGRATE' ;
NUM_ROWS CHAIN_CNT
---------- ----------
2 1
SQL> select file#,block# ,rowid from (select dbms_rowid.rowid_relative_fno(rowid
) file#,dbms_rowid.rowid_block_number(rowid) block# ,rowid from MIGRATE);
FILE# BLOCK# ROWID
---------- ---------- ------------------
4 3685 AAANSQAAEAAAA5lAAA
4 3685 AAANSQAAEAAAA5lAAB~~~rowid没变
SQL> alter system dump datafile 4 block 3685;
系统已更改。
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
col 1: [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 2
-H-FL-- 可以看到 这行 头和尾都在一个块中
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 file# number;
SQL> variable blk# number;
SQL> execute :file#:=dbms_utility.data_block_address_file(to_number('1000e66','x
xxxxxx'));
PL/SQL 过程已成功完成。
SQL> execute :blk#:=dbms_utility.data_block_address_block(to_number('1000e66','
xxxxxxx'));
PL/SQL 过程已成功完成。
SQL> print file#
FILE#
----------
4
SQL> print blk#
BLK#
----------
3686
SQL> alter system dump datafile 4 block 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 也是一个指针 指向原来迁移的位置的块
col 0: [2000]
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'));
PL/SQL 过程已成功完成。
SQL> execute :blk#:=dbms_utility.data_block_address_block(to_number('1000e65','
xxxxxxx'));
PL/SQL 过程已成功完成。
SQL> print file#
FILE#
----------
4
SQL> print blk#
BLK#
----------
3685
可以看出正是 迁移前所在的位置
关于消除row migrate 有很多种方法
1.MOVE 方法
SQL> ANALYZE TABLE migrate LIST CHAINED ROWS;
表已分析。
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
---------- ----------
2 0
消除了 (注意move 会让index失效,而且 LOCK表)
2.EXP/IMP 方法
SQL> create table migrate2 (a char(2000), b char(2000),c char(2000));
表已创建。
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(*)
------------------------------ ----------
MIGRATE2 1
SQL> ANALYZE TABLE MIGRATE2 COMPUTE STATISTICS;
表已分析。
SQL> select num_rows,chain_cnt from dba_tables where table_name='MIGRATE2' ;
NUM_ROWS CHAIN_CNT
---------- ----------
2 1
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.
连接到: 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 行
成功终止导出, 没有出现警告。
SQL> truncate table migrate2;
表被截断。
C:\>imp xh/a831115 file=e:\exp\migrate2.dmp tables=migrate2 ignore=y
Import: Release 10.2.0.1.0 - Production on 星期日 10月 25 00:05:16 2009
Copyright (c) 1982, 2005, Oracle. All rights reserved.
连接到: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
经由常规路径由 EXPORT:V10.02.01 创建的导出文件
已经完成 ZHS16GBK 字符集和 AL16UTF16 NCHAR 字符集中的导入
. 正在将 XH 的对象导入到 XH
. 正在将 XH 的对象导入到 XH
. . 正在导入表 "MIGRATE2"导入了 2 行
成功终止导入, 没有出现警告。
SQL> ANALYZE TABLE MIGRATE2 COMPUTE STATISTICS;
表已分析。
SQL> select num_rows,chain_cnt from dba_tables where table_name='MIGRATE2' ;
NUM_ROWS CHAIN_CNT
---------- ----------
2 0
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');
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));
表已创建。
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(*)
------------------------------ ----------
MIGRATE3 1
SQL> ANALYZE TABLE MIGRATE3 COMPUTE STATISTICS;
表已分析。
SQL> select num_rows,chain_cnt from dba_tables where table_name='MIGRATE3' ;
NUM_ROWS CHAIN_CNT
---------- ----------
2 1
SQL> create table migrate3_test as select * from migrate3 where rowid in (select
head_rowid from chained_rows where table_name='MIGRATE3');
表已创建。
SQL> delete migrate3 where rowid in (select head_rowid from chained_rows where t
able_name='MIGRATE3');
已删除 1 行。
SQL> commit;
提交完成。
SQL> insert into migrate3 select * from MIGRATE3_TEST;
已创建 1 行。
SQL> commit
2 ;
提交完成。
SQL> drop TABLE MIGRATE3_TEST;
表已删除。
SQL> ANALYZE TABLE MIGRATE3 COMPUTE STATISTICS;
表已分析。
SQL> select num_rows,chain_cnt from dba_tables where table_name='MIGRATE3' ;
NUM_ROWS CHAIN_CNT
---------- ----------
2 0
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));
表已创建。
SQL> ed
已写入 file afiedt.buf
1 declare
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 /
PL/SQL 过程已成功完成。
SQL>
SQL> select count(distinct a) from cm;
COUNT(DISTINCTA)
----------------
1001
SQL> select count(distinct b) from cm;
COUNT(DISTINCTB)
----------------
1001
SQL>
可以 看到这个表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';
SEGMENT_NA FILE_ID BLOCK_ID BLOCKS
---------- ---------- ---------- ----------
CM 4 2329 8
CM 4 2353 8
SQL> select file_id,block_id,blocks from dba_extents where segment_name='CM';
FILE_ID BLOCK_ID BLOCKS
---------- ---------- ----------
4 2329 8
4 2353 8
SQL> select distinct block# from (select dbms_rowid.rowid_relative_fno(rowid) f
ile#,dbms_rowid.rowid_block_number(rowid) block# ,rowid from CM);
BLOCK#
----------
2333
2353
2354
2357
2358
2359
2332
2334
2335
2336
2355
BLOCK#
----------
2356
2360
已选择13行。
SQL>
SQL> alter table xh.cm move compress;
表已更改。
SQL> select segment_name,file_id,block_id,blocks from dba_extents where segment
_name='CM';
SEGMENT_NA FILE_ID BLOCK_ID BLOCKS
---------- ---------- ---------- ----------
CM 4 2361 8
CM 4 2369 8
SQL> select file_id,block_id,blocks from dba_extents where segment_name='CM';
FILE_ID BLOCK_ID BLOCKS
---------- ---------- ----------
4 2361 8
4 2369 8
SQL> select distinct block# from (select dbms_rowid.rowid_relative_fno(rowid) f
ile#,dbms_rowid.rowid_block_number(rowid) block# ,rowid from CM);
BLOCK#
----------
2364
2367
2368
2369
2371
2365
2366
2370
已选择8行。
~~~~~~~~~~~~~~~~可以看到使用的 块减少了(13减少为8)
转储结构看下
SQL> alter system dump datafile 4 block 2364;
系统已更改。
data_block_dump,data header at 0x80c227c
===============
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
tab 1, row 0, @0x1f4e
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个字段)
.................................
tab 1, row 714, @0x115c
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~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~指针指向符号表,存储的实际值,就是这样大量的指针指向符号表
关于compress与 row migrate
如果执行UPDATE 将造成row migrate 表变大.
SQL> analyze table cm compute statistics;
表已分析。
SQL> select num_rows,chain_cnt from dba_tables where table_name='CM' ;
NUM_ROWS CHAIN_CNT
---------- ----------
2000 0
SQL> update cm set b='c';
已更新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
---------- ----------
2000 844
一个update操作产生大量row migrate
SQL> alter system dump datafile 4 block 2364;
系统已更改。
tl: 9 fb: --H----- lb: 0x2 cc: 0
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';
SEGMENT_NA FILE_ID BLOCK_ID BLOCKS
---------- ---------- ---------- ----------
CM 4 2361 8
CM 4 2369 8
CM 4 2409 8~~~~~~~~~~~~可以看到表变大了(原来是2个区,现在3个区)
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/12020513/viewspace-611339/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/12020513/viewspace-611339/