Oracle索引梳理系列(九)- 淺談聚簇因子對索引使用的影響及優化方法


版權聲明:本文發布於http://www.cnblogs.com/yumiko/,版權由Yumiko_sunny所有,歡迎轉載。轉載時,請在文章明顯位置注明原文鏈接。若在未經作者同意的情況下,將本文內容用於商業用途,將保留追究其法律責任的權利。如果有問題,請以郵箱方式聯系作者(793113046@qq.com)。


 1、聚簇因子的概念

  • 聚簇因子,是CBO優化器決定是否使用索引的因素之一,主要反映索引塊上的數據(順序存儲),與該索引基於的表塊上的數據(無序存儲)的順序相似程度的差異性。即表數據的存儲順序是否與相應索引數據的存儲順序一致。
  • 通過查詢dba_indexes視圖、user_indexes視圖以及all_indexes視圖的CLUSTERING_FACTOR列,可以了解當前索引的聚簇因子值。

 

 

2、索引塊與相應數據塊之間數據分布產生差異的原因

  • 對於索引塊的數據存儲,這里以普通btree索引為例,索引塊中鍵值的分布總是有序的,且根據鍵值及其相應的rowid信息,唯一定位一行記錄在相應表的數據塊中的分布。理想情況下,相同或相鄰的鍵值,盡量定位在相同的數據塊上,可以避免對於數據塊多余的I/O操作。

  • 對於數據塊的數據存儲,並不是有序存儲的。且ORACLE為節省空間,會優先使用當前當水位線(HWM)以下的可用數據塊,而不是按序使用最后被使用的塊。當HWM以下無可用數據塊時,再開辟新的數據塊使用。
  • 正因為數據塊中數據存儲的特點,隨着時間的推移,數據在相應數據塊間的分布越發零散,進而影響索引塊中,相同或相鄰鍵值對應的相應數據行信息(rowid),所指向的數據塊越加分散,進而導致聚簇因子變差。

 

 

3、聚簇因子的計算方法

聚簇因子大致的計算方法順序如下:

  1. 進行一次索引全掃描
  2. 檢查索引塊中的rowid信息。比較前一個rowid與一個rowid是否指向同一個數據塊。若不同,則聚簇因子加1.
  3. 當完成整個的索引掃面后,即得到該索引的聚簇因子的數值。

 

 

4、聚簇因子好壞的判斷 

良好的CF值,會趨向於數據表的塊數。

較差的CF值,會趨向於數據表的行數。

需要注意的是:隨着時間的推移,頻繁的DML操作,會讓CF值總是趨向於惡劣方向發展。

 

示例:

本示例主要說明CF的趨勢性。

--查看當前測試表中索引的聚簇因子情況
--注意此時的LAST_ANALYZED為空,說明未收集過統計信息
Yumiko_sunny@OA01> select INDEX_NAME,b.TABLE_NAME,CLUSTERING_FACTOR, 2 a.BLOCKS tb_blocks,b.NUM_ROWS tb_rows, 3 to_char(c.LAST_ANALYZED,'YYYY-MM-DD HH24:MI:SS') LAST_ANALYZED 4 from dba_segments a,dba_indexes b ,dba_tables c 5 where a.segment_name=b.table_name 6 and a.segment_name=c.table_name 7 and b.table_name='TEST'; INDEX_NAME TABLE_NAME CLUSTERING_FACTOR TB_BLOCKS TB_ROWS LAST_ANALYZED --------------- --------------- ----------------- ---------- ---------- ------------------- TEST_IDX TEST 17381 18432 1217342 --分析收集表test最新的統計信息 Yumiko_sunny@OA01> analyze table test compute statistics; Table analyzed.
--查看收集后最新的信息,可以看到,結果集中CF值,明顯小於數據塊值,說明此時情況相似度很好。 Yumiko_sunny@OA01> select INDEX_NAME,b.TABLE_NAME,CLUSTERING_FACTOR, 2 a.BLOCKS tb_blocks,b.NUM_ROWS tb_rows, 3 to_char(c.LAST_ANALYZED,'YYYY-MM-DD HH24:MI:SS') LAST_ANALYZED 4 from dba_segments a,dba_indexes b ,dba_tables c 5 where a.segment_name=b.table_name 6 and a.segment_name=c.table_name 7 and b.table_name='TEST'; INDEX_NAME TABLE_NAME CLUSTERING_FACTOR TB_BLOCKS TB_ROWS LAST_ANALYZED --------------- --------------- ----------------- ---------- ---------- ------------------- TEST_IDX TEST 17381 18432 1217342 2016-11-06 16:38:08 --插入新的數據並進行提交 Yumiko_sunny@OA01> insert into test select * from test; 1217342 rows created. Yumiko_sunny@OA01> commit; Commit complete. --再次收集表test相關的統計信息 Yumiko_sunny@OA01> analyze table test compute statistics; Table analyzed. --不難發現,隨着insert的操作,CF值發生了改變,雖然目前該值在可接受范圍內,但已經開始趨向行數。
--可以想象下,一個生產環境中,除了insert,還有update跟delete,隨着這些操作的增多,勢必更加趨向行數。 Yumiko_sunny@OA01> select INDEX_NAME,b.TABLE_NAME,CLUSTERING_FACTOR, 2 a.BLOCKS tb_blocks,b.NUM_ROWS tb_rows, 3 to_char(c.LAST_ANALYZED,'YYYY-MM-DD HH24:MI:SS') LAST_ANALYZED 4 from dba_segments a,dba_indexes b ,dba_tables c 5 where a.segment_name=b.table_name 6 and a.segment_name=c.table_name 7 and b.table_name='TEST'; INDEX_NAME TABLE_NAME CLUSTERING_FACTOR TB_BLOCKS TB_ROWS LAST_ANALYZED --------------- --------------- ----------------- ---------- ---------- ------------------- TEST_IDX TEST 206123 35840 2434684 2016-11-06 16:39:58


 

 

5、聚簇因子的優化

由於影響CF(CLUSTERING_FACTOR)值的主要取決於數據表的數據,在數據塊中的存儲分布情況,因此優化CF的重點還是在調整數據表本身,具體方法如下:

  • 定期按索引列順序重建表
    • 建議通過dbms_metadata.get_ddl提取表結構完整的DDL語句,結合insert order by column以及rename table的方式進行表的重建。
    • 不建議采用CTAS方式(create table as select),該方式可能引起后續不必要的麻煩。具體影響可參閱鏈接中的案例 http://blog.csdn.net/leshami/article/details/7362156
  • 使用聚簇表代替普通的數據表
    • 頻繁DML的表以及經常需要全表掃描的表,不適合建立聚簇表。
    • 具體查閱作者前面關於“表簇索引”一文的介紹 “Oracle索引種類之表簇索引(cluster index)

 

示例:

本示例承接上面的示例,主要演示通過重建表的方式進行聚簇因子優化的過程。

--再次確認原始表test的CF值
Yumiko_sunny@OA01> select INDEX_NAME,b.TABLE_NAME,CLUSTERING_FACTOR, 2 a.BLOCKS tb_blocks,b.NUM_ROWS tb_rows, 3 to_char(c.LAST_ANALYZED,'YYYY-MM-DD HH24:MI:SS') LAST_ANALYZED 4 from dba_segments a,dba_indexes b ,dba_tables c 5 where a.segment_name=b.table_name 6 and a.segment_name=c.table_name 7 and b.table_name='TEST'; INDEX_NAME TABLE_NAME CLUSTERING_FACTOR TB_BLOCKS TB_ROWS LAST_ANALYZED --------------- --------------- ----------------- ---------- ---------- ------------------- TEST_IDX TEST 206123 35840 2434684 2016-11-06 22:10:51
--通過調用dbms_metadata包的get_ddl函數,抽取原始表test的DDL結構語句
Yumiko_sunny@OA01> set long 100000 Yumiko_sunny@OA01> set pages 0 Yumiko_sunny@OA01> select dbms_metadata.get_ddl('TABLE',upper('&table_name'),upper('&owner')) from dual; Enter value for table_name: TEST Enter value for owner: SCOTT old 1: select dbms_metadata.get_ddl('TABLE',upper('&table_name'),upper('&owner')) from dual new 1: select dbms_metadata.get_ddl('TABLE',upper('TEST'),upper('SCOTT')) from dual CREATE TABLE "SCOTT"."TEST" ( "OWNER" VARCHAR2(30), "OBJECT_NAME" VARCHAR2(128), "SUBOBJECT_NAME" VARCHAR2(30), "OBJECT_ID" NUMBER, "DATA_OBJECT_ID" NUMBER, "OBJECT_TYPE" VARCHAR2(19), "CREATED" DATE, "LAST_DDL_TIME" DATE, "TIMESTAMP" VARCHAR2(19), "STATUS" VARCHAR2(7), "TEMPORARY" VARCHAR2(1), "GENERATED" VARCHAR2(1), "SECONDARY" VARCHAR2(1), "NAMESPACE" NUMBER, "EDITION_NAME" VARCHAR2(30) ) SEGMENT CREATION IMMEDIATE PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT) TABLESPACE "USERS"

--利用抽取的原始表test的結構語句,創建新表test_tmp Yumiko_sunny@OA01> CREATE TABLE "SCOTT"."TEST_TMP" 2 ( "OWNER" VARCHAR2(30), 3 "OBJECT_NAME" VARCHAR2(128), 4 "SUBOBJECT_NAME" VARCHAR2(30), 5 "OBJECT_ID" NUMBER, 6 "DATA_OBJECT_ID" NUMBER, 7 "OBJECT_TYPE" VARCHAR2(19), 8 "CREATED" DATE, 9 "LAST_DDL_TIME" DATE, 10 "TIMESTAMP" VARCHAR2(19), 11 "STATUS" VARCHAR2(7), 12 "TEMPORARY" VARCHAR2(1), 13 "GENERATED" VARCHAR2(1), 14 "SECONDARY" VARCHAR2(1), 15 "NAMESPACE" NUMBER, 16 "EDITION_NAME" VARCHAR2(30) 17 ) SEGMENT CREATION IMMEDIATE 18 PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 19 NOCOMPRESS LOGGING 20 STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 21 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 22 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT) 23 TABLESPACE "USERS"; Table created. --通過對原始表test的索引列進行order by排序操作后,差入到新表test_tmp中
--通過append hint的方法,雖然可以減少redo的產生,並且在hwm以上開辟數據塊,加快了數據的加載速度。
--但該方式,在commit或者rollback事物前,其他會話無法針對該表進行DML操作,生產環境中需要注意。
Yumiko_sunny@OA01> insert into /*+append */ test_tmp select * from test order by object_id; 2434684 rows created. Yumiko_sunny@OA01> commit;
--為新表test_tmp的索引列添加索引
Yumiko_sunny@OA01> create index test_idx_new on test_tmp(object_id); Index created. --將原始表test進行重命名test_old Yumiko_sunny@OA01> alter table test rename to test_old; Table altered. --將新表test_tmp重命名為test Yumiko_sunny@OA01> alter table test_tmp rename to test; Table altered. --分析收集新表test的統計信息 Yumiko_sunny@OA01> analyze table TEST compute statistics; Table analyzed.

--查看新建的表test的CF,不難發現,此時的CF值將較之前已經明顯下降。
--至此,CF的優化過程結束。
Yumiko_sunny@OA01> select INDEX_NAME,b.TABLE_NAME,CLUSTERING_FACTOR, 2 a.BLOCKS tb_blocks,b.NUM_ROWS tb_rows, 3 to_char(c.LAST_ANALYZED,'YYYY-MM-DD HH24:MI:SS') LAST_ANALYZED 4 from dba_segments a,dba_indexes b ,dba_tables c 5 where a.segment_name=b.table_name 6 and a.segment_name=c.table_name 7 and b.table_name='TEST'; INDEX_NAME TABLE_NAME CLUSTERING_FACTOR TB_BLOCKS TB_ROWS LAST_ANALYZED ---------------------------------------------------------------------------------------- TEST_IDX_NEW TEST 39700 35840 2434684 2016-11-06 22:26:10

 

需要補充說明的是:
對於alter table move的操作,可以降低高水位線,但對於優化聚簇因子值而言,意義不大。
對於重建索引,通過實驗發現(只進行了兩個實驗,可能結果集存在誤差),聚簇因子值不但未降低,有時還存在些許的增加,需要注意。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM