一、概述:
如果你的Oracle數(shù)據(jù)庫性能低下,行鏈接和行遷移可能是其中的原因之一。我們能夠通過合理的設(shè)計(jì)或調(diào)整數(shù)據(jù)庫來阻止這個(gè)現(xiàn)象。
行鏈接和行遷移是能夠被避免的兩個(gè)潛在性問題。我們可以通過合理的調(diào)整來提高數(shù)據(jù)庫性能。本文主要描述的是:
什么是行遷移與行鏈接
如何判斷行遷移與行鏈接
如何避免行遷移與行鏈接
10年積累的成都網(wǎng)站建設(shè)、網(wǎng)站制作經(jīng)驗(yàn),可以快速應(yīng)對(duì)客戶對(duì)網(wǎng)站的新想法和需求。提供各種問題對(duì)應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識(shí)你,你也不認(rèn)識(shí)我。但先網(wǎng)站制作后付款的網(wǎng)站建設(shè)流程,更有綏江免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
當(dāng)使用索引讀取單行時(shí),行遷移影響OLTP系統(tǒng)。最糟糕的情形是,對(duì)所有讀取操作而言,增加了額外的I/O。行鏈接則影響索引讀和全表掃描。
注:在翻譯行(row)時(shí)使用記錄來描述(便于理解),如第一行,使用第一條記錄。
二、Oralce 塊
操作系統(tǒng)塊的大小是操作系統(tǒng)讀寫的最小操作單元,也是操作系統(tǒng)文件的屬性之一。當(dāng)創(chuàng)建一個(gè)數(shù)據(jù)庫時(shí),選擇一個(gè)基于操作系統(tǒng)塊的
整數(shù)倍大小作為Oracle數(shù)據(jù)庫塊的大小。Oracle數(shù)據(jù)庫讀寫操作則是以O(shè)racle塊為最小單位,而非操作系統(tǒng)塊。一旦設(shè)置了Oracle數(shù)據(jù)塊的大小,
則在整個(gè)數(shù)據(jù)庫生命期間不能被更改(除 Oracle 9i之外)。因此為Oracle數(shù)據(jù)庫定制合理的Oralce塊大小,象預(yù)期數(shù)據(jù)庫總大小以及并發(fā)用戶數(shù)這些
因素應(yīng)當(dāng)予以考慮。
數(shù)據(jù)庫塊由下列邏輯結(jié)構(gòu)(在整個(gè)數(shù)據(jù)庫結(jié)構(gòu)下)
SELECT x,d,e FROM row_mig_chain_demo WHERE x = 3;
SELECT a.name, b.value
FROM v$statname a, v$mystat b
WHERE a.statistic# = b.statistic#
AND lower(a.name) = 'table fetch continued row';
NAME VALUE
---------------------------------------------------------------- ----------
table fetch continued row 2
--現(xiàn)在當(dāng)我們通過主鍵索引掃描從記錄3的尾部提取數(shù)據(jù)時(shí),這將增加table fetch continued row的值。因?yàn)樾枰獜男械念^部和尾部獲取數(shù)據(jù)來組合。
--現(xiàn)在來看看全表掃描是否也有相同的影響。
SELECT * FROM row_mig_chain_demo;
X
----------
3
2
1
SELECT a.name, b.value
FROM v$statname a, v$mystat b
WHERE a.statistic# = b.statistic#
AND lower(a.name) = 'table fetch continued row';
NAME VALUE
---------------------------------------------------------------- ----------
table fetch continued row 3
--此時(shí)table fetch continued row的值被增加,因?yàn)椴坏貌粚?duì)記錄3的尾部進(jìn)行融合。而記錄1和2即便是存在遷移現(xiàn)象,但由于是全表掃描,
--因此不會(huì)增加table fetch continued row的值。
SELECT x,a FROM row_mig_chain_demo;
X
----------
3
2
1
SELECT a.name, b.value
FROM v$statname a, v$mystat b
WHERE a.statistic# = b.statistic#
AND lower(a.name) = 'table fetch continued row';
NAME VALUE
---------------------------------------------------------------- ----------
table fetch continued row 3
--當(dāng)需要提取的數(shù)據(jù)是整個(gè)表上的頭兩列的時(shí)候,此時(shí)table fetch continued row也不會(huì)增加。因?yàn)椴恍枰獙?duì)記錄3進(jìn)行數(shù)據(jù)融合。
SELECT x,e FROM row_mig_chain_demo;
X
----------
3
2
1
SELECT a.name, b.value
FROM v$statname a, v$mystat b
WHERE a.statistic# = b.statistic#
AND lower(a.name) = 'table fetch continued row';
NAME VALUE
---------------------------------------------------------------- ----------
table fetch continued row 4
--但是當(dāng)提取列d和e的時(shí)候,table fetch continued row的值被增加。通常查詢時(shí)容易產(chǎn)生行遷移即使是真正存在行鏈接,因?yàn)槲覀兊牟樵?
--所需的列通常位于表的前幾列。
八、如何鑒別行鏈接和行遷移
--聚合統(tǒng)計(jì)所創(chuàng)建的表,這也將使得重構(gòu)整行而發(fā)生table fetch continued row
SELECT count(e) FROM row_mig_chain_demo;
COUNT(E)
----------
1
SELECT a.name, b.value
FROM v$statname a, v$mystat b
WHERE a.statistic# = b.statistic#
AND lower(a.name) = 'table fetch continued row';
NAME VALUE
---------------------------------------------------------------- ----------
table fetch continued row 5
--通過analyze table來校驗(yàn)表上的鏈接數(shù)
ANALYZE TABLE row_mig_chain_demo COMPUTE STATISTICS;
SELECT chain_cnt
FROM user_tables
WHERE table_name = 'ROW_MIG_CHAIN_DEMO';
CHAIN_CNT
----------
3
--3條記錄是鏈接的。顯然,他們中的兩條記錄是遷移(記錄1,記錄2)和一記錄是鏈接(記錄3).
--實(shí)例啟動(dòng)后的table fetch continued row的總數(shù)
--視圖v$mystat告訴我們自從實(shí)例啟動(dòng)后,所有的表上共有多少次為table fetch continued row.
sqlplus system/
SELECT 'Chained or Migrated Rows = '||value
FROM v$sysstat
WHERE name = 'table fetch continued row';
Chained or Migrated Rows = 31637
--上面的查詢結(jié)果表明,可能有1個(gè)表上存在行鏈接被fetch了31637次,也可能有31637個(gè)表,每個(gè)表上有一個(gè)行鏈接,每次fetch一次。也有
--可能是上述情況的組合。
--31637次也許是好的,也許是壞的,僅僅是一個(gè)值而已。
--這取決于
--數(shù)據(jù)庫啟動(dòng)了多久?
--這個(gè)值占總提取數(shù)據(jù)百分比的多少行?
--假如它占據(jù)了你從表上fetch的0.001%,則無關(guān)緊要。
--因此,比較table fetch continued row與總提取的記錄數(shù)是有必要的
SELECT name,value FROM v$sysstat WHERE name like '%table%';
NAME VALUE
---------------------------------------------------------------- ----------
table scans (short tables) 124338
table scans (long tables) 1485
table scans (rowid ranges) 0
table scans (cache partitions) 10
table scans (direct read) 0
table scan rows gotten 20164484
table scan blocks gotten 1658293
table fetch by rowid 1883112
table fetch continued row 31637
table lookup prefetch client count 0
九、一個(gè)表上鏈接的行是多少?
--通過對(duì)表analyze后(未analyze是空值),可以從數(shù)據(jù)字典user_tales獲得鏈接的記錄數(shù)。
ANALYZE TABLE row_mig_chain_demo COMPUTE STATISTICS;
SELECT chain_cnt,
round(chain_cnt/num_rows*100,2) pct_chained,
avg_row_len, pct_free , pct_used
FROM user_tables
WHERE table_name = 'ROW_MIG_CHAIN_DEMO';
CHAIN_CNT PCT_CHAINED AVG_ROW_LEN PCT_FREE PCT_USED
---------- ----------- ----------- ---------- ----------
3 100 3691 10 40
--PCT_CHAINED 為100%,表明所有的行都是鏈接的或遷移的。
十、列出鏈接行
當(dāng)使用analyze table中的list chained rows子句能夠列出一個(gè)表上的鏈接行。該命令的結(jié)果是將所有的鏈接上存儲(chǔ)到一個(gè)由list chained rows子句
顯示指定的表中。 這些結(jié)構(gòu)有助于決定是否將來有足夠的空間實(shí)現(xiàn)行更新。
創(chuàng)建CHAINED_ROWS 表
創(chuàng)建一個(gè)用于存儲(chǔ)analyze ... list chained rows命令結(jié)果的表,可以執(zhí)行位于$ORACLE_HOME/rdbms/admin目錄下的UTLCHAIN.SQL或UTLCHN1.SQL 腳本。
這個(gè)腳本會(huì)在當(dāng)前schema下創(chuàng)建一個(gè)名為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
);
當(dāng)chained_rows表創(chuàng)建后,可以使用analyze table命令來指向該表作為輸出。
十一、如何避免行鏈接和行遷移
增加pctfree能夠幫助避免行鏈接。如果我們?yōu)閴K留下更多的可用空間,則行上有空間滿足將來的增長(zhǎng)。也可以對(duì)那些有較高刪除率的表采用重新組織
或重建表索引來避免行鏈接與行遷移。如果表上有些行被頻繁的刪除,則數(shù)據(jù)塊上會(huì)有更多的空閑空間。當(dāng)被插入的行后續(xù)擴(kuò)展,則被插入的行可能會(huì)
分布到那些被刪除的行上而仍然沒有更多空間來用于擴(kuò)展。重新組織表則確保主要的空閑空間是完整的空塊。
ALTER TABLE ... MOVE 命令允許對(duì)一個(gè)未分區(qū)或分區(qū)的表上的數(shù)據(jù)進(jìn)行重新分配到一個(gè)新的段。也可以分配到一個(gè)有配額的不同的表空間。該命令也允許
你在不能使用alter table的情形下來修改表或分區(qū)上的一些存儲(chǔ)屬性。也可以使用ALTER TABLE ... MOVE 命令中的compress關(guān)鍵字在存儲(chǔ)到新段時(shí)使用壓縮選項(xiàng)。
[sql] view plain copy
1. ALTER TABLE MOVE
使用alter table move 之前首先統(tǒng)計(jì)每個(gè)塊上的行數(shù).
SELECT dbms_rowid.rowid_block_number(rowid) "Block-Nr", count(*) "Rows"
FROM row_mig_chain_demo
GROUP BY dbms_rowid.rowid_block_number(rowid) order by 1;
Block-Nr Rows
---------- ----------
2066 3
--現(xiàn)在消除表上的行鏈接,使用alter table move來重建row_mig_chain_demo表到一個(gè)新段,指定一些新的存儲(chǔ)選項(xiàng)。
ALTER TABLE row_mig_chain_demo MOVE
PCTFREE 20
PCTUSED 40
STORAGE (INITIAL 20K
NEXT 40K
MINEXTENTS 2
MAXEXTENTS 20
PCTINCREASE 0);
Table altered.
--在alter table move之后再次統(tǒng)計(jì)每一塊上的行數(shù)
SELECT dbms_rowid.rowid_block_number(rowid) "Block-Nr", count(*) "Rows"
FROM row_mig_chain_demo
GROUP BY dbms_rowid.rowid_block_number(rowid) order by 1;
Block-Nr Rows
---------- ----------
2322 1
2324 1
2325 1
2. 重建表上的索引
--移動(dòng)一個(gè)表將使得表上記錄的rowid發(fā)生變化。這將引起表上的索引被置為unusable狀態(tài)?;谠摫硎褂盟饕腄ML語句將收到ORA-01502 錯(cuò)誤。
--因此表上的索引必須被刪除或重建。同樣地,表上的統(tǒng)計(jì)信息也會(huì)變得無效。因此統(tǒng)計(jì)信息在表移動(dòng)之后也應(yīng)當(dāng)重新收集。
ANALYZE TABLE row_mig_chain_demo COMPUTE STATISTICS;
ERROR at line 1:
ORA-01502: index 'SCOTT.SYS_C003228' or partition of such index is in unusable state
--表上的主鍵必須被重建
ALTER INDEX SYS_C003228 REBUILD;
Index altered.
ANALYZE TABLE row_mig_chain_demo COMPUTE STATISTICS;
Table analyzed.
SELECT chain_cnt,
round(chain_cnt/num_rows*100,2) pct_chained,
avg_row_len, pct_free , pct_used
FROM user_tables
WHERE table_name = 'ROW_MIG_CHAIN_DEMO';
CHAIN_CNT PCT_CHAINED AVG_ROW_LEN PCT_FREE PCT_USED
---------- ----------- ----------- ---------- ----------
1 33.33 3687 20 40
--如果表包含LOB 列,用戶可以指定該命令連同LOB數(shù)據(jù)段以及LOB索引段(同該表相關(guān))一起移動(dòng)(move)。
--當(dāng)未指定時(shí),則LOB數(shù)據(jù)段以及LOB索引段不參與移動(dòng)。
十二、檢測(cè)所有表上的行連接與行遷移
可以通過CHAINED_ROWS 表獲取所有表上的行鏈接與行遷移。
1.創(chuàng)建chained_rows表
cd $ORACLE_HOME/rdbms/admin
sqlplus scott/tiger
@utlchain.sql
2.ananlyze 所有表/或指定表
SELECT 'ANALYZE TABLE '||table_name||' LIST CHAINED ROWS INTO CHAINED_ROWS;'
FROM user_tables
/
ANALYZE TABLE ROW_MIG_CHAIN_DEMO LIST CHAINED ROWS INTO CHAINED_ROWS;
ANALYZE TABLE DEPT LIST CHAINED ROWS INTO CHAINED_ROWS;
ANALYZE TABLE EMP LIST CHAINED ROWS INTO CHAINED_ROWS;
ANALYZE TABLE BONUS LIST CHAINED ROWS INTO CHAINED_ROWS;
ANALYZE TABLE SALGRADE LIST CHAINED ROWS INTO CHAINED_ROWS;
ANALYZE TABLE DUMMY LIST CHAINED ROWS INTO CHAINED_ROWS;
Table analyzed.
3.查看行鏈接的rowid
SELECT owner_name,
table_name,
count(head_rowid) row_count
FROM chained_rows
GROUP BY owner_name,table_name
/
OWNER_NAME TABLE_NAME ROW_COUNT
------------------------------ ------------------------------ ----------
SCOTT ROW_MIG_CHAIN_DEMO 1
通過該方式可以快速的定位一個(gè)表上有多少行鏈接問題的。如果行鏈接或行遷移較多,則應(yīng)當(dāng)基于該表增加pctfree的值 或重建該表。
十三、結(jié)論:
行遷移影響OLTP系統(tǒng)使用索引讀取單行。最糟糕的情形所對(duì)所有的讀都增加額外的I/O。而行鏈接則影響索引讀和全表掃描。
行遷移通常由update操作引起
行鏈接通常有insert操作引起
基于行鏈接或行遷移的查詢或創(chuàng)建(如索引)由于需要更多的I/O將降低數(shù)據(jù)庫的性能
調(diào)試行鏈接或行遷移使用analyze 命令,查詢v$sysdate視圖
移出行鏈接或行遷移使用更大的pctfree參數(shù)或使用alter table move命令
十四、關(guān)于作者
原文鏈接: The Secrets of Oracle Row Chaining and Migration
Martin Zahn, Akadia AG, Information Technology, CH-3672 Oberdiessbach
EMail: martin dot zahn at akadia dot ch
12.09.2007: Updated for Oracle 10.2