ORACLE-SQL優化

ORACLE 採用兩種訪問表中記錄的方式:http://blog.csdn.net/zhangao0086/article/details/6250777

a.  全表掃描

全表掃描就是順序地訪問表中每條記錄. ORACLE採用一次讀入多個數據塊(database block)的方式優化全表掃描.

b.  通過ROWID訪問表

你可以採用基於ROWID的訪問方式情況,提高訪問表的效率, , ROWID包含了表中記錄的物理位置信息.ORACLE採

用索引(INDEX)實現了數據和存放數據的物理位置(ROWID)之間的聯繫. 通常索引提供了快速訪問ROWID的方法,

因此那些基於索引列的查詢就可以得到性能上的提高.


現在來說一些能夠增加效率的方法,爲了方便測試,我建立了兩個測試表:

IDS_EMP:image,EMPNO上有索引,表中有100W條記錄image

IDS_DEPTimage,DEPTNO上有索引,表中記錄:image

並且爲了保證結果更加真實,在每次執行語句之前,都清空共享池:

alter system flush buffer_cache(注意:需要權限!)

1.選擇最有效率的表名順序(只在基於規則的優化器中有效)

首先先設置規則的優化器,使用語句:

alter system set optimizer_mode=RULE;

ORACLE的解析器按照從右到左的順序處理FROM子句中的表名,因此FROM子句中寫在最後的表(我們稱它爲驅動表或基礎表,driving table)將被最先處理. 在FROM子句中包含多個表的情況下,你必須選擇記錄條數最少的表作爲基礎表.當ORACLE處理多個表時, 會運用排序及合併的方式連接它們.首先,掃描第一個表(FROM子句中最後的那個表)並對記錄進行排序,然後掃描第二個表(FROM子句中最後第二個表),最後將所有從第二個表中檢索出的記錄與第一個表中合適記錄進行合併.

選擇記錄多的DES_EMP作基礎表進行表連接:

image

選擇記錄少的DES_DEPT作基礎表進行表連接:

image

注:我是執行完之後,才把select語句選上,目的是方便大家看.

2.WHERE子句中的連接順序

ORACLE採用自下而上的順序解析WHERE子句,根據這個原理,表之間的連接必須寫在其他WHERE條件之前, 那些可以過濾掉最大數量記錄的條件必須寫在WHERE子句的末尾.

高效:

image

低效:

image

3.SELECT子句中避免使用*

當你想在SELECT子句中列出所有的COLUMN時,使用動態SQL列引用 ‘*' 是一個方便的方法.不幸的是,這是一個非常低效的方法.   
實際上,ORACLE在解析的過程中, 會將'*' 依次轉換成所有的列名, 這個工作是通過查詢數據字典完成的, 這意味着將耗費更多的時間.

4.計算記錄條數

和一般的觀點相反, count(*) 比count(1)稍快 , 當然如果可以通過索引檢索,對索引列的計數仍舊是最快的. 例如 COUNT(EMPNO)   
(在論壇中曾經對此有過相當熱烈的討論, 這個觀點並不十分準確,通過實際的測試,上述三種方法並沒有顯著的性能差別).

設置基於規則的優化器:alter system set optimizer_mode=RULE

image

image

image

5.用WHERE子句替換HAVING子句

避免使用HAVING子句, HAVING 只會在檢索出所有記錄之後纔對結果集進行過濾. 這個處理需要排序,總計等操作. 如果能通過WHERE子句限制記錄的數目,那就能減少這方面的開銷.

高效:

image

低效:

image

(HAVING 中的條件一般用於對一些集合函數的比較,如COUNT() 等等. 除此而外,一般的條件應該寫在WHERE子句中)

6.使用表的別名(Alias)

當在SQL語句中連接多個表時, 請使用表的別名並把別名前綴於每個Column上.這樣一來,就可以減少解析的時間並減少那些由Column歧義引起的語法錯誤.  
(Column歧義指的是由於SQL中不同的表具有相同的Column名,當SQL語句中出現這個Column時,SQL解析器無法判斷這個Column的歸屬)

7.用EXISTS替代IN

在許多基於基礎表的查詢中,爲了滿足一個條件,往往需要對另一個表進行聯接.在這種情況下, 使用EXISTS(或NOT EXISTS)通常將提高查詢的效率.

設置基於規則的優化器:alter system set optimizer_mode=RULE

image

image

8.用NOT EXISTS替代NOT IN

在子查詢中,NOT IN子句將執行一個內部的排序和合並. 無論在哪種情況下,NOT IN都是最低效的 (因爲它對子查詢中的表執行了一個全表遍歷). 爲了避免使用NOT IN ,我們可以把它改寫成外連接(Outer Joins)或NOT EXISTS.

image

image

9.用表連接替換EXISTS

通常來說 , 採用表連接的方式比EXISTS更有效率

10.用EXISTS替換DISTINCT

當提交一個包含一對多表信息(比如部門表和僱員表)的查詢時,避免在SELECT子句中使用 DISTINCT. 一般可以考慮用EXIST替換

image

image

11.常量的計算是在語句被優化時一次性完成的,而不是在語句每次執行時

假設要檢索月薪大於2000的表達式:

sal > 24000/12  
sal > 2000   
sal*12 > 24000

如果SQL語句包括第一種情況,優化器會簡單地把它轉變成第二種。  
優化器不會簡化跨越比較符的表達式,例如第三條語句,鑑於此,應儘量寫用常量跟字段比較檢索的表達式,而不要將字段置於表達式當中。否則沒有辦法優化,比如如果sal上有索引,第一條和第二條就可以使用(執行索引),第三條就難以使用,因爲它會把(sal*12)當作一個字段,於是不識別索引

12.IN、OR子句常會使用工作表,使索引失效

如果不產生大量重複值,可以考慮把子句拆開。拆開的子句中應該包含索引。

13.消除對大型錶行數據的順序存取

在嵌套查詢中,對錶的順序存取對查詢效率可能產生致命的影響。比如採用順序存取策略,一個嵌套3層的查詢,如果每層都查詢1000行,那麼這個查詢就要查詢 10億行數據。避免這種情況的主要方法就是對連接的列進行索引。例如,兩個表:學生表(學號、姓名、年齡)和選課表(學號、課程號、成績)。如果兩個表要做連接,就要在“學號”這個連接字段上建立索引。  
還可以使用並集來避免順序存取。儘管在所有的檢查列上都有索引,但某些形式的WHERE子句強迫優化器使用順序存取。

使用設置基於基於成本的優化器來測試:alter system set optimizer_mode=ALL_ROWS scope=both

下面的查詢將強迫對ide_emp表執行順序操作:

image

image

注:UNION 操作符用於合併兩個或多個 SELECT 語句的結果集。

UNION 內部的 SELECT 語句必須擁有相同數量的列。列也必須擁有相似的數據類型。同時,每條 SELECT 語句中的列的順序必須相同。

14.避免相關子查詢

一個列的標籤同時在主查詢和WHERE子句中的查詢中出現,那麼很可能當主查詢中的列值改變之後,子查詢必須重新查詢一次。查詢嵌套層次越多,效率越低,因此應當儘量避免子查詢。如果子查詢不可避免,那麼要在子查詢中過濾掉儘可能多的行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章