索引聚簇因子用於測量相對於某個索引值(如僱員姓氏)的行順序。被索引值的行存儲得越有序,則聚簇因子越低。因爲我們常用的表是堆表,數據的存儲是“無序”存放在磁盤或存儲上;如果所查的數據越無序越分散,查詢的邏輯IO
雖然一樣,但是物理IO的代價就可能很高了。
如果聚簇因子較高,則在大型索引範圍掃描過程中,數據庫將執行相對較高數目的I/O。索引條目指向隨機表塊,因此數據庫可能必須一遍又一遍地來回重讀索引所指向的同一數據塊。
如果聚簇因子較低,則在大型索引範圍掃描過程中數據庫將執行相對較低數目的I/O。在一個範圍內的索引鍵傾向於指向相同的數據塊,因此該數據庫不必來回重讀相同的數據塊。
例如:
場景:以姓氏爲順序存放多條數據,並放置多個數據塊上,
假設在姓氏列上存在一個索引。每個姓氏條目對應於一個 rowid。從概念上講,索引條目看起來如下所示:
Abel,block1row1
Ande,block1row2
Atkinson,block1row3
Austin,block1row4
Baer,block1row5
假設在僱員 ID 列上存在另一個單獨的索引。從概念上講,索引條目可能看起來像下面這樣,僱員 id幾乎分佈在這整個兩個數據塊的任意位置:
100,block1row50
101,block2row1
102,block1row9
103,block2row19
104,block2row39
105,block1row4
.
.
通過ALL_INDEXES 查看這兩個索引的聚簇因子。EMP_NAME_IX 的聚簇因子較低,這意味着在一個單一葉塊中的相鄰索引條目傾向於指向同一個數據塊中的行。
EMP_EMP_ID_PK 的聚簇因子較高,這意味着在相同的葉塊中的相鄰索引條目不太可能指向同一個數據塊中的行。
數據庫版本:
SQL> select * from v$version ;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - Production
PL/SQL Release 11.2.0.3.0 - Production
CORE 11.2.0.3.0 Production
TNS for Linux: Version 11.2.0.3.0 - Production
NLSRTL Version 11.2.0.3.0 - Production
索引塊無序存儲情況下:
SQL> create table t_f as select * from dba_objects where 0=1;
Table created.
SQL> begin
2 for i in 1..10 loop
3 insert into t_f select * from dba_objects order by i;
4 commit;
5 end loop;
6 end;
7 /
PL/SQL procedure successfully completed.
SQL> set wrap off
SQL> col owner for a10
SQL> col segment_name for a15
SQL> select owner, segment_name, blocks, extents,bytes/1024/1024||'M' "size" from dba_segments where owner='SCOTT' and segment_name='T_F';
OWNER SEGMENT_NAME BLOCKS EXTENTS size
---------- --------------- ---------- ---------- -------------------------------
SCOTT T_F 11136 82 87M
SQL> select count(1) from t_f ;
COUNT(1)
----------
753430
SQL> col owner for a10;
SQL> col index_name for a10;
SQL> select owner,index_name, clustering_factor, num_rows from dba_indexes where owner='SCOTT' and index_name=upper('idx_t_f_id');
OWNER INDEX_NAME CLUSTERING_FACTOR NUM_ROWS
---------- ---------- ----------------- ----------
SCOTT IDX_T_F_ID 753430 753430 ====>從這裏可以看出聚簇因子與行數是一樣的,通過統計信息的收集也是一樣,如下,說明每次讀一條記錄都會產生一個物理IO
SQL> exec dbms_stats.gather_table_stats('SCOTT','T_F',cascade => true);
PL/SQL procedure successfully completed.
SQL> select owner,index_name, clustering_factor, num_rows from dba_indexes where owner='SCOTT' and index_name=upper('idx_t_f_id');
OWNER INDEX_NAME CLUSTERING_FACTOR NUM_ROWS
---------- ---------- ----------------- ----------
SCOTT IDX_T_F_ID 753430 753430
SQL> select blocks from dba_tables where table_name='T_F';
BLOCKS
----------
10989
索引塊有序存儲情況下:
SQL> create table t_f2 as select * from dba_objects where 0=1;
Table created.
SQL> insert into t_f2 select * from t_f order by object_id;
753430 rows created.
SQL> commit;
Commit complete.
SQL> select count(1) from t_f2;
COUNT(1)
----------
753430
SQL> create index idx_t_f2_id on t_f2(object_id);
Index created.
SQL> select owner, segment_name, segment_type,blocks, extents,bytes/1024/1024||'M' "SIZE" from dba_segments where owner='SCOTT' and segment_name=upper('idx_t_f2_id');
truncating (as requested) before column EXTENTS
OWNER SEGMENT_NAME SEGMENT_TYPE BLOCKS SIZE
---------- --------------- ------------------------------------ ---------- -----
SCOTT IDX_T_F2_ID INDEX 1792 14M
SQL> select owner,index_name, clustering_factor, num_rows from dba_indexes where owner='SCOTT' and index_name=upper('idx_t_f2_id');
OWNER INDEX_NAME CLUSTERING_FACTOR NUM_ROWS
---------- ---------- ----------------- ----------
SCOTT IDX_T_F2_ID 12155 753430===>從這裏可以看出聚簇因子與block數相似,通過統計信息的收集也是一樣
SQL> exec dbms_stats.gather_table_stats('SCOTT','T_F2',cascade => true);
PL/SQL procedure successfully completed.
SQL> select owner,index_name, clustering_factor, num_rows from dba_indexes where owner='SCOTT' and index_name=upper('idx_t_f2_id');
OWNER INDEX_NAME CLUSTERING_FACTOR NUM_ROWS
---------- ---------- ----------------- ----------
SCOTT IDX_T_F2_ID 12155 753430
SQL> select blocks from dba_tables where table_name='T_F2';
BLOCKS
----------
11117
一些簡單總結:
1)、整個索引掃描完畢後,就得到了該索引的cluster factor;
2)、如果ClusteringFactor接近於表存儲的塊數,說明這張表是按照索引字段的順序存儲的,最佳狀態就是兩個數值相等,但是在生產庫上,很難發現活躍的表時這種理想狀態;
3)、 如果ClusteringFactor接近於行的數量,那說明這張表不是按索引字段順序存儲的,這樣就可能導致多次去訪問同一個塊,導致產生多次物理IO;
4)、影響這個因素的最佳操作方法就是重建表,然後重新順序導入數據,不過一般很難做到
5)、這個參數能幫助我們瞭解,有時候,是否走索引,並非就是數據量佔據100%的因素,我很少能影響這個這個因素
雖然一樣,但是物理IO的代價就可能很高了。
如果聚簇因子較高,則在大型索引範圍掃描過程中,數據庫將執行相對較高數目的I/O。索引條目指向隨機表塊,因此數據庫可能必須一遍又一遍地來回重讀索引所指向的同一數據塊。
如果聚簇因子較低,則在大型索引範圍掃描過程中數據庫將執行相對較低數目的I/O。在一個範圍內的索引鍵傾向於指向相同的數據塊,因此該數據庫不必來回重讀相同的數據塊。
例如:
場景:以姓氏爲順序存放多條數據,並放置多個數據塊上,
假設在姓氏列上存在一個索引。每個姓氏條目對應於一個 rowid。從概念上講,索引條目看起來如下所示:
Abel,block1row1
Ande,block1row2
Atkinson,block1row3
Austin,block1row4
Baer,block1row5
假設在僱員 ID 列上存在另一個單獨的索引。從概念上講,索引條目可能看起來像下面這樣,僱員 id幾乎分佈在這整個兩個數據塊的任意位置:
100,block1row50
101,block2row1
102,block1row9
103,block2row19
104,block2row39
105,block1row4
.
.
通過ALL_INDEXES 查看這兩個索引的聚簇因子。EMP_NAME_IX 的聚簇因子較低,這意味着在一個單一葉塊中的相鄰索引條目傾向於指向同一個數據塊中的行。
EMP_EMP_ID_PK 的聚簇因子較高,這意味着在相同的葉塊中的相鄰索引條目不太可能指向同一個數據塊中的行。
數據庫版本:
SQL> select * from v$version ;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - Production
PL/SQL Release 11.2.0.3.0 - Production
CORE 11.2.0.3.0 Production
TNS for Linux: Version 11.2.0.3.0 - Production
NLSRTL Version 11.2.0.3.0 - Production
索引塊無序存儲情況下:
SQL> create table t_f as select * from dba_objects where 0=1;
Table created.
SQL> begin
2 for i in 1..10 loop
3 insert into t_f select * from dba_objects order by i;
4 commit;
5 end loop;
6 end;
7 /
PL/SQL procedure successfully completed.
SQL> set wrap off
SQL> col owner for a10
SQL> col segment_name for a15
SQL> select owner, segment_name, blocks, extents,bytes/1024/1024||'M' "size" from dba_segments where owner='SCOTT' and segment_name='T_F';
OWNER SEGMENT_NAME BLOCKS EXTENTS size
---------- --------------- ---------- ---------- -------------------------------
SCOTT T_F 11136 82 87M
SQL> select count(1) from t_f ;
COUNT(1)
----------
753430
SQL> col owner for a10;
SQL> col index_name for a10;
SQL> select owner,index_name, clustering_factor, num_rows from dba_indexes where owner='SCOTT' and index_name=upper('idx_t_f_id');
OWNER INDEX_NAME CLUSTERING_FACTOR NUM_ROWS
---------- ---------- ----------------- ----------
SCOTT IDX_T_F_ID 753430 753430 ====>從這裏可以看出聚簇因子與行數是一樣的,通過統計信息的收集也是一樣,如下,說明每次讀一條記錄都會產生一個物理IO
SQL> exec dbms_stats.gather_table_stats('SCOTT','T_F',cascade => true);
PL/SQL procedure successfully completed.
SQL> select owner,index_name, clustering_factor, num_rows from dba_indexes where owner='SCOTT' and index_name=upper('idx_t_f_id');
OWNER INDEX_NAME CLUSTERING_FACTOR NUM_ROWS
---------- ---------- ----------------- ----------
SCOTT IDX_T_F_ID 753430 753430
SQL> select blocks from dba_tables where table_name='T_F';
BLOCKS
----------
10989
索引塊有序存儲情況下:
SQL> create table t_f2 as select * from dba_objects where 0=1;
Table created.
SQL> insert into t_f2 select * from t_f order by object_id;
753430 rows created.
SQL> commit;
Commit complete.
SQL> select count(1) from t_f2;
COUNT(1)
----------
753430
SQL> create index idx_t_f2_id on t_f2(object_id);
Index created.
SQL> select owner, segment_name, segment_type,blocks, extents,bytes/1024/1024||'M' "SIZE" from dba_segments where owner='SCOTT' and segment_name=upper('idx_t_f2_id');
truncating (as requested) before column EXTENTS
OWNER SEGMENT_NAME SEGMENT_TYPE BLOCKS SIZE
---------- --------------- ------------------------------------ ---------- -----
SCOTT IDX_T_F2_ID INDEX 1792 14M
SQL> select owner,index_name, clustering_factor, num_rows from dba_indexes where owner='SCOTT' and index_name=upper('idx_t_f2_id');
OWNER INDEX_NAME CLUSTERING_FACTOR NUM_ROWS
---------- ---------- ----------------- ----------
SCOTT IDX_T_F2_ID 12155 753430===>從這裏可以看出聚簇因子與block數相似,通過統計信息的收集也是一樣
SQL> exec dbms_stats.gather_table_stats('SCOTT','T_F2',cascade => true);
PL/SQL procedure successfully completed.
SQL> select owner,index_name, clustering_factor, num_rows from dba_indexes where owner='SCOTT' and index_name=upper('idx_t_f2_id');
OWNER INDEX_NAME CLUSTERING_FACTOR NUM_ROWS
---------- ---------- ----------------- ----------
SCOTT IDX_T_F2_ID 12155 753430
SQL> select blocks from dba_tables where table_name='T_F2';
BLOCKS
----------
11117
一些簡單總結:
1)、整個索引掃描完畢後,就得到了該索引的cluster factor;
2)、如果ClusteringFactor接近於表存儲的塊數,說明這張表是按照索引字段的順序存儲的,最佳狀態就是兩個數值相等,但是在生產庫上,很難發現活躍的表時這種理想狀態;
3)、 如果ClusteringFactor接近於行的數量,那說明這張表不是按索引字段順序存儲的,這樣就可能導致多次去訪問同一個塊,導致產生多次物理IO;
4)、影響這個因素的最佳操作方法就是重建表,然後重新順序導入數據,不過一般很難做到
5)、這個參數能幫助我們瞭解,有時候,是否走索引,並非就是數據量佔據100%的因素,我很少能影響這個這個因素