CLUSTERING_FACTOR、回表、資料分佈傾斜走全表還是索引

lusklusklusk發表於2017-08-07
CLUSTERING_FACTOR Indicates the amount of order of the rows in the table based on the values of the index.
■ If the value is near the number of blocks, then the
table is very well ordered. In this case, the index
entries in a single leaf block tend to point to rows in
the same data blocks.
■ If the value is near the number of rows, then the
table is very randomly ordered. In this case, it is
unlikely that index entries in the same leaf block
point to rows in the same data blocks.

Assessing I/O for Blocks, not Rows
Oracle Database performs I/O by blocks. Therefore, the optimizer's decision to use full table scans is influenced by the percentage of blocks accessed, not rows. This is called the index clustering factor. If blocks contain single rows, then rows accessed and blocks accessed are the same.
However, most tables have multiple rows in each block. Consequently, the desired number of rows may be clustered in a few blocks or spread out over a larger number of blocks.
Although the clustering factor is a property of the index, the clustering factor actually relates to the spread of similar indexed column values within data blocks in the table. A lower clustering factor indicates that the individual rows are concentrated within fewer blocks in the table. Conversely, a high clustering factor indicates that the individual rows are scattered more randomly across blocks in the table. Therefore, a high clustering factor means that it costs more to use a range scan to fetch rows by rowid, because more blocks in the table need to be visited to return the data
索引掃描取OR全表掃描決於:
1、

where條件囊括的資料鍵值在索引上能夠找到,詳見NULL相關知識點


2、
where條件囊括的資料塊佔整表資料塊範圍比較小為什麼是資料塊,而非資料行數?主要是因為有一個索引聚類因子的概念

Oracle資料庫透過塊執行I/O。 因此,最佳化器使用全表掃描的決定受到訪問塊的百分比而不是行的影響。 這稱為索引聚類因子。 如果塊包含單行,則訪問的行和訪問的塊是相同的。
但是,大多數表在每個塊中都有多行。 因此,期望數量的行可以聚集在幾個塊中或者擴充套件到更大的數目的塊。
雖然聚類因子是索引的屬性,但聚類因子實際上與表中資料塊內類似索引列值的擴充套件有關。 較低的聚類因子表示各行集中在表中較少的塊中。 相反,高聚類因子表明單獨的行在表中的塊之間更隨機地散佈。 因此,高聚類因素意味著使用範圍掃描以rowid獲取行花費更多,因為表中的更多塊需要被訪問才能返回資料



檢視ALL_INDEXES的CLUSTERING_FACTOR*值來判斷資料的離散程度
假如表的總塊數是5000個塊,有1000000行,如果表的資料太離散,帶上where 條件object_id=100的資料只有10000行(1%的資料),但是分佈在太多不同的塊上假如就是5000個塊,走索引10000次就需要訪問5000個資料塊,成本IO等於5000資料塊+索引塊數>整表塊數,那肯定走全表掃描了。
如果表的資料不那麼離散,object_id=100的資料分佈就在200個塊上,成本IO等於200資料塊+索引塊數<整表塊數,那肯定走索引掃描了。


如下三種資料傾斜情況
SQL> select * from test where object_id=1;--資料佔95%,理應走全表
SQL> select * from test where object_id=2;--資料佔1%,理應走索引
SQL> select * from test where object_id=3;--資料佔1%,理應走索引

如果CLUSTERING_FACTOR值是建議走索引。
比如第一個語句,它也不會走全表而是直接走了索引
比如表的總塊數是100個塊(可能有空塊或半空塊),object_id=1卻只佔據了50個塊,select全表掃描時會掃描HWM以內的所有塊,即100個塊
但是索引掃描時,只是去定位到那50個塊,成本為索引塊+50資料塊<全表的100資料塊

如果CLUSTERING_FACTOR值是建議走全表。
上面第二、三個語句,它也不會走索引而是直接走了全表


一個索引塊中索引值如下
A
A
A
B
B
B
C
C
C

三個資料塊中資料分佈如下1
A
B
C

A
B
C

A
B
C

三個資料塊中資料分佈如下2
A
A
A

B
B
B

C
C
C

按分佈1的情況,找到對應行,需要9次IO
A要訪問3個資料塊
B要訪問3個資料塊
C要訪問3個資料塊
總計需要訪問9次資料塊

按分佈2的情況,找到對應行,需要3次IO
A要訪問1個資料塊
B要訪問1個資料塊
C要訪問1個資料塊
總計需要訪問3次資料塊




回表開銷:索引儲存索引列的值和rowid,可以透過rowid定位回到表中,得到這個索引列以外的列資訊,要做這個類事,必然有開銷

其實回表,不就是去訪問表中某些具體的行嘛,如果回表涉及的行的資料塊數量佔整表所有行資料塊數量的80%,那不就是回表成本太高嗎,所以回表和資料離散程度相關

按上面的例子,回表要回10000次,比全表掃描1000000行開銷總要少吧
比如不走索引,直接select * from table,總計1000000,難道不就是回表1000000次嗎

針對查詢較少列的sql,還可以透過建立複合索引,使sql一次將資料從索引段中讀取出來,不用回表。 
select id,name from tab_t where id=1;而(id,name)是複合索引,這種情況下就不用回表。 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/30126024/viewspace-2143207/,如需轉載,請註明出處,否則將追究法律責任。

相關文章