Oracle的Index-1(轉)

Rounders發表於2007-08-06

Oracle的Index-1

[@more@]

作者:heyongzhou | 來自:不詳 | 點選:387 | 釋出:2001-11-8

索引( Index )是常見的資料庫物件,它的設定好壞、使用是否得當,極大地影響資料庫應用程式和Database 的效能。雖然有許多資料講索引的用法, DBA 和 Developer 們也經常與它打交道,但筆者發現,還是有不少的人對它存在誤解,因此針對使用中的常見問題,講三個問題。此文所有示例所用的資料庫是 Oracle 8.1.7 OPS on HP N series ,示例全部是真實資料,讀者不需要注意具體的資料大小,而應注意在使用不同的方法後,資料的比較。本文所講基本都是陳詞濫調,但是筆者試圖透過實際的例子,來真正讓您明白事情的關鍵。

一講,索引並非總是最佳選擇

如果發現Oracle 在有索引的情況下,沒有使用索引,這並不是Oracle 的最佳化器出錯。在有些情況下,Oracle 確實會選擇全表掃描(Full Table Scan),而非索引掃描(Index Scan)。這些情況通常有:
1, 表未做statistics, 或者 statistics 陳舊,導致 Oracle 判斷失誤。
2, 根據該表擁有的記錄數和資料塊數,實際上全表掃描要比索引掃描更快。

對第1種情況,最常見的例子,是以下這句sql 語句:
select count(*) from mytable;
在未作statistics 之前,它使用全表掃描,需要讀取6000多個資料塊(一個資料塊是8k), 做了statistics 之後,使用的是 INDEX (FAST FULL SCAN) ,只需要讀取450個資料塊。但是,statistics 做得不好,也會導致Oracle 不使用索引。

第2種情況就要複雜得多。一般概念上都認為索引比錶快,比較難以理解什麼情況下全表掃描要比索引掃描快。為了講清楚這個問題,這裡先介紹一下Oracle 在評估使用索引的代價(cost)時兩個重要的資料:CF(Clustering factor) 和 FF(Filtering factor).
CF: 所謂 CF, 通俗地講,就是每讀入一個索引塊,要對應讀入多少個資料塊。
FF: 所謂 FF, 就是該sql 語句所選擇的結果集,佔總的資料量的百分比。
大約的計算公式是:FF * (CF + 索引塊個數) ,由此估計出,一個查詢, 如果使用某個索引,會需要讀入的資料塊塊數。需要讀入的資料塊越多,則 cost 越大,Oracle 也就越可能不選擇使用 index. (全表掃描需要讀入的資料塊數等於該表的實際資料塊數)
其核心就是, CF 可能會比實際的資料塊數量大。CF 受到索引中資料的排列方式影響,通常在索引剛建立時,索引中的記錄與表中的記錄有良好的對應關係,CF 都很小;在表經過大量的插入、修改後,這種對應關係越來越亂,CF 也越來越大。此時需要 DBA 重新建立或者組織該索引。
如果某個sql 語句以前一直使用某索引,較長時間後不再使用,一種可能就是 CF 已經變得太大,需要重新整理該索引了。
FF 則是Oracle 根據 statistics 所做的估計。比如, mytables 表有32萬行,其主鍵myid的最小值是1,最大值是409654,考慮以下sql 語句:
Select * from mytables where myid>=1; 和
Select * from mytables where myid>=400000
這兩句看似差不多的 sql 語句,對Oracle 而言,卻有巨大的差別。因為前者的 FF 是100%, 而後者的 FF 可能只有 1%。如果它的CF 大於實際的資料塊數,則Oracle 可能會選擇完全不同的最佳化方式。而實際上,在我們的資料庫上的測試驗證了我們的預測. 以下是在HP 上執行時它們的 explain plan:
第一句:
SQL> select * from mytables where myid>=1;

已選擇325917行。
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=3132 Card=318474 Byt es=141402456)
1 0 TABLE ACCESS (FULL) OF 'MYTABLES' (Cost=3132 Card=318474 Byt es=141402456)
Statistics
----------------------------------------------------------
7 recursive calls
89 db block gets
41473 consistent gets
19828 physical reads
0 redo size
131489563 bytes sent via SQL*Net to client
1760245 bytes received via SQL*Net from client
21729 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
325917 rows processed

第二句:

Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=346 Card=663 Bytes=2 94372)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'MYTABLES' (Cost=346 Card=663
Bytes=294372)
2 1 INDEX (RANGE SCAN) OF 'PK_MYTABLES' (UNIQUE) (Cost=5 Card=663)

Statistics
----------------------------------------------------------
1278 recursive calls
0 db block gets
6647 consistent gets
292 physical reads
0 redo size
3544898 bytes sent via SQL*Net to client
42640 bytes received via SQL*Net from client
524 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
7838 rows processed

顯而易見,第1句沒有使用索引,第2句使用了主鍵索引pk_mytables. FF的巨大影響由此可見一斑。由此想到,我們在寫sql 語句時,如果預先估計一下 FF, 你就幾乎可以預見到 Oracle 會否使用索引。

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

相關文章