ORACLE 聚簇因子優化
聚簇因子:資料表中的資料都是無序的存在庫中,當我們對資料進行檢索的時候,查詢起來很是耗費資源,於是我們就需要為表建立索引,索引的作用就是把表中的資料按照一定的順序排列儲存起來,於是就出現了一個問題,有的表中的資料和索引排列的順序很是相近,而另一些表中的資料和索引排列的順序相距甚遠,聚簇因子的作用就是用來標記這個的,聚簇因子越小,相似度越高,聚簇因子越大,相似度越低。
資料和索引相似度:ORACLE 在儲存資料時,並不是按照資料塊的順序挨個進行存入資料,因為前面存入的資料經常會有DML或者DDL操作,刪除資料後,原先存有資料的資料塊就變成了空塊,ORACLE為了節省儲存空間,當資料庫再次有新資料進行插入的話,就會優先使用那些空塊,只有當空塊不夠使用的時候,才會去高水位上開闢新塊,這種情況也就會導致,一張表中的資料,並不是儲存在相鄰的資料塊中,於是聚簇因子變的很大,當這種情況進行邏輯讀取的時候,就會增加IO的次數, 影響讀取的速度。
測試:
建表:
CREATE TABLE t_1 AS SELECT ROWNUM rn,a.* FROM all_objects a ORDER BY object_name DESC;
--建立t_1表關於rownum索引
CREATE INDEX ind_t_1 ON t_1(rn);
--建立表表t_2
CREATE TABLE t_2 AS SELECT * FROM ( SELECT ROWNUM rn,a.* FROM all_objects a ) ORDER BY rn ASC;
--建立t_2表關於rownum索引
CREATE INDEX ind_t_2 ON t_2(rn);
--分析兩張表及其索引
EXEC DBMS_STATS.gather_table_stats(USER, 'T_1');
EXEC DBMS_STATS.gather_table_stats(USER, 'T_2');
EXEC DBMS_STATS.gather_index_stats(USER, 'IND_T_1');
EXEC DBMS_STATS.gather_index_stats(USER, 'IND_T_2');
執行查詢操作
SQL> set autotrace traceonly;
SQL> SELECT * FROM t_1 WHERE rn BETWEEN 100 AND 120;
21 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 923245147
--------------------------------------------------------------------------------
-------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Tim
e |
--------------------------------------------------------------------------------
-------
| 0 | SELECT STATEMENT | | 22 | 2244 | 14 (0)| 00:
00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T_1 | 22 | 2244 | 14 (0)| 00:
00:01 |
|* 2 | INDEX RANGE SCAN | IND_T_1 | 22 | | 2 (0)| 00:
00:01 |
--------------------------------------------------------------------------------
-------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("RN">=100 AND "RN"<=120)
Statistics
----------------------------------------------------------
445 recursive calls
0 db block gets
85 consistent gets
0 physical reads
0 redo size
3426 bytes sent via SQL*Net to client
427 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
4 sorts (memory)
0 sorts (disk)
21 rows processed
表二查詢:
SELECT * FROM t_2 WHERE rn BETWEEN 100 AND 120;
21 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 2193767187
--------------------------------------------------------------------------------
-------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Tim
e |
--------------------------------------------------------------------------------
-------
| 0 | SELECT STATEMENT | | 22 | 2244 | 3 (0)| 00:
00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T_2 | 22 | 2244 | 3 (0)| 00:
00:01 |
|* 2 | INDEX RANGE SCAN | IND_T_2 | 22 | | 2 (0)| 00:
00:01 |
--------------------------------------------------------------------------------
-------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("RN">=100 AND "RN"<=120)
Statistics
----------------------------------------------------------
445 recursive calls
0 db block gets
69 consistent gets
0 physical reads
0 redo size
3426 bytes sent via SQL*Net to client
427 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
4 sorts (memory)
0 sorts (disk)
21 rows processed
觀察結果:
通過執行統計資訊觀察,T_1表的查詢一致讀是85,而T_2表的一致讀只有69,周樣的表結構,同樣的資料,為何有這麼大的差距呢。
分析:
SQL> select b.table_name, a.index_name, b.num_rows, b.blocks, a.clustering_factor from user_indexes a, user_tables b where b.table_name in('T_1','T_2') and a.table_name = b.table_name;
TABLE_NAME INDEX_NAME NUM_ROWS BLOCKS CLUSTERING_FACTOR
------------------------------ -------------------- ---------- ---------- -----------------
T_1 IND_T_1 71761 1069 38034
T_2 IND_T_2 71763 1069 1069
通過查詢聚簇因子發現,兩個表的聚簇因子差別很大,基於RN的索引在RN是順序排列的表中,CLUSTERING_FACTOR的值相差很大。
在表中資料有時候屬於無序狀態,這個時候的CLUSTERING_FACTOR比較接近NUM_ROWS,說明如果掃描整個表,每次都要根據INDEX來讀取相應行的ROWID,這個時候的IO操作很多,自然檢索時間會比較長。如果資料有序的話,CLUSTERING_FACTOR比較接近BLOCKS,說明相鄰的資料在一個塊中,減少了IO運算元量,自然檢索時間會大大降低。
解決辦法:
第一種辦法:對錶進行重構:alter table t_1 move;
SQL> alter table t_1 move;
(
alter table move;
可以用來降低HWM,也可以用來調整已使用的block的儲存引數,
比如PCTFREE。
等於在當前tablespace中重組table。
注意這個操作後,需要rebuild index
)
Table altered.
再次查詢聚簇因子:
SQL> select b.table_name, a.index_name, b.num_rows, b.blocks, a.clustering_factor from user_indexes a, user_tables b where b.table_name in('T_1','T_2') and a.table_name = b.table_name;
TABLE_NAME INDEX_NAME NUM_ROWS BLOCKS CLUSTERING_FACTOR
------------------------------ -------------------- ---------- ---------- -----------------
T_1 IND_T_1 71761 1069 38034
T_2 IND_T_2 71763 1069 1069
發現還是一樣。
第二種方法: 按照索引順序重建表:
SQL> create table t_1_bk as select * from t_1 order by rn;
Table created.
建立索引:
create index ind_t1bk on t_1_bk(rn);
Index created.
統計索引
EXEC DBMS_STATS.gather_index_stats(USER, 'IND_T1BK');
再次檢視聚簇因子:
select b.table_name, a.index_name, b.num_rows, b.blocks, a.clustering_factor from user_indexes a, user_tables b where b.table_name in('T_1_BK','T_2') and a.table_name = b.table_name;
TABLE_NAME INDEX_NAME NUM_ROWS BLOCKS CLUSTERING_FACTOR
------------------------------ -------------------- ---------- ---------- -----------------
T_1_BK IND_T1BK 1069
T_2 IND_T_2 71763 1069 1069
可以看到聚簇因子有所降低,但沒了NUM_ROWS與BLOCKS。
在這裡沒有這兩個欄位的值是因為user_indexes 和user_tables的資訊來自於對錶的統計資訊。
SQL> exec dbms_stats.gather_table_stats(USER,'T_1_BK');
PL/SQL procedure successfully completed.
SQL> select b.table_name, a.index_name, b.num_rows, b.blocks, a.clustering_factor from user_indexes a, user_tables b where b.table_name in('T_1_BK','T_2') and a.table_name = b.table_name;
TABLE_NAME INDEX_NAME NUM_ROWS BLOCKS CLUSTERING_FACTOR
------------------------------ -------------------- ---------- ---------- -----------------
T_1_BK IND_T1BK 71761 1069 1069
T_2 IND_T_2 71763 1069 1069
以上這種辦法只針對於小表, 但如果這個表的資料量非常大就不能夠使用這種辦法了。
第三種方法: 針對大表的:分割槽
線上將表改為分割槽表:
EXEC DBMS_REDEFINITION.CAN_REDEF_TABLE(USER, 'T_1',dbms_redefinition.cons_index);
EXEC DBMS_REDEFINITION.CAN_REDEF_TABLE(USER, 'T_1',dbms_redefinition.cons_index);
PL/SQL procedure successfully completed.
獲得建立表的語句:select dbms_metadata.get_ddl('TABLE','T_1','SYS') from dual;
獲得建立INDEX的語句:select dbms_metadata.get_ddl('INDEX','IND_T_1','SYS') from dual;
建立表:
create table t_1new(RN NUMBER,
OWNER VARCHAR2(30) NOT NULL ENABLE,
OBJECT_NAME VARCHAR2(30) NOT NULL ENABLE,
SUBOBJECT_NAME VARCHAR2(30),
OBJECT_ID NUMBER NOT NULL ENABLE,
DATA_OBJECT_ID NUMBER,
OBJECT_TYPE VARCHAR2(19),
CREATED DATE NOT NULL ENABLE,
LAST_DDL_TIME DATE NOT NULL ENABLE,
TIMESTAMP VARCHAR2(19),
STATUS VARCHAR2(7),
TEMPORARY VARCHAR2(1),
GENERATED VARCHAR2(1),
SECONDARY VARCHAR2(1),
NAMESPACE NUMBER NOT NULL ENABLE,
EDITION_NAME VARCHAR2(30)) partition by range(rn)
(partition p1 values less than(20000),
partition p2 values less than(40000),
partition p3 values less than(60000),
partition p4 values less than(maxvalue));
建立索引:create index ind_t_1new on t_1new(rn);
EXEC DBMS_REDEFINITION.START_REDEF_TABLE(USER, 'T_1', 'T_1NEW', 'RN RN, OWNER OWNER, OBJECT_NAME OBJECT_NAME, SUBOBJECT_NAME SUBOBJECT_NAME, OBJECT_ID OBJECT_ID, DATA_OBJECT_ID DATA_OBJECT_ID, OBJECT_TYPE OBJECT_TYPE, CREATED CREATED, LAST_DDL_TIME LAST_DDL_TIME, TIMESTAMP TIMESTAMP, STATUS STATUS, TEMPORARY TEMPORARY, GENERATED GENERATED, SECONDARY SECONDARY, NAMESPACE NAMESPACE, EDITION_NAME EDITION_NAME', DBMS_REDEFINITION.CONS_INDEX);
exec dbms_redefinition.finish_redef_table('HR','T_1','T_1NEW');
PL/SQL procedure successfully completed.
驗證查詢:
SQL> select count(*) from t_1 partition(p1);
COUNT(*)
----------
19999
SQL> select count(*) from t_1 partition(p2);
COUNT(*)
----------
20000
分割槽成功! 我們這時再來看看聚簇因子:
select b.table_name, a.index_name, b.num_rows, b.blocks, a.clustering_factor from user_indexes a, user_tables b where b.table_name in('T_1') and a.table_name = b.table_name;
SQL> select b.table_name, a.index_name, b.num_rows, b.blocks, a.clustering_factor from user_indexes a, user_tables b where b.table_name in('T_1') and a.table_name = b.table_name;
TABLE_NAME INDEX_NAME NUM_ROWS BLOCKS CLUSTERING_FACTOR
------------------------------ -------------------- ---------- ---------- -----------------
T_1 IND_T_1NEW 38104
! 無解! 咋個不行。 應該是理解問題了, 這個只能解決聚簇因子所帶來的效能問題。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/196700/viewspace-751488/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 【效能優化】Oracle 效能優化:降低列值聚簇因子 提高查詢效率優化Oracle
- 聚簇因子的理解
- 關於索引聚簇因子(CLUSTERING_FACTOR)引起的sql優化過程索引SQL優化
- 【效能最佳化】Oracle 效能最佳化:降低列值聚簇因子 提高查詢效率Oracle
- Oracle聚簇表Oracle
- 聚簇因子和執行計劃的聯絡
- 淺談索引系列之聚簇因子(clustering_factor)索引
- clustering factor索引聚簇因子和執行計劃索引
- 一次簡單的效能優化診斷,聚簇因子過高導致全表掃描。優化
- 聊聊Oracle聚簇Cluster(上)Oracle
- oracle 聚簇表學習Oracle
- 淺談聚簇索引與非聚簇索引索引
- 聚簇索引索引
- 【實驗】【聚簇】聚簇(Cluster)和聚簇表(Cluster Table)的建立與總結
- MySQL中的聚簇索引和非聚簇索引MySql索引
- MySQL聚簇索引和非聚簇索引的原理及使用MySql索引
- 一分鐘明白MySQL聚簇索引和非聚簇索引MySql索引
- 聚簇表簡介
- 資料庫表,索引(索引組織表,聚簇表,聚簇索引,)資料庫索引
- 聚簇索引和非聚簇索引到底有什麼區別?索引
- 一看就懂的MySQL的聚簇索引,以及聚簇索引是如何長高的MySql索引
- InnoDB學習(八)之 聚簇索引索引
- MySQL 聚簇索引 和覆蓋索引MySql索引
- Oracle的簇與簇表Oracle
- 資料庫聚簇索引——not null條件對唯一鍵索引成為聚簇索引的影響資料庫索引Null
- oracle簇clusterOracle
- MySQL 聚簇索引一定是主鍵嗎MySql索引
- MySQL innodb如何選擇一個聚簇索引MySql索引
- oracle中的簇Oracle
- oracle index 聚集因子OracleIndex
- MVO優化DBSCAN實現聚類優化聚類
- 【Mysql】InnoDB 中的聚簇索引、二級索引、聯合索引MySql索引
- 理解索引和聚簇——效能調整手冊和參考索引
- [MySQL]為什麼非聚簇索引不儲存資料位置MySql索引
- 基於Barra多因子模型的組合權重優化模型優化
- 基於因子圖優化的鐳射IMU融合SLAM學習優化SLAM
- 起源自天文學的PostgreSQL優化器成本因子校對SQL優化
- 什麼是Oracle簇(CLUSTER)表Oracle