oracle實驗記錄 (ROW 壓縮,遷移,連結)

fufuh2o發表於2009-08-04

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/,如需轉載,請註明出處,否則將追究法律責任。

相關文章