Oracle優化技巧

現觀察線上系統運行發現,線上某些業務查詢存在等待時間長問題,後覈查發現,部分問題出如今對數據庫操做上Cost大部分時間,後根據網上各位前輩提供的優化技巧解決大部分問題,現寫下本篇文章,一來鞏固加深本身學習的優化技巧,二來方便正在爲sql優化迷茫的猿友們提供一下思路和方法,共同進步,一塊兒成長~

一、現狀描述

sql執行時間長、數據查詢慢

二、問題對象

sql執行語句(特別是多表多條件關聯查詢數據)

三、理論知識

一、Oracle優化器
Oracle優化器:Oracle數據庫中的優化器又叫查詢優化器(QueryOptimizer)。它是SQL分析和執行的優化工具,它負責生成、制定SQL的執行計劃。
    
Oracle優化器優化方式
基於規則的優化方式(Rule-BasedOptimization,簡稱爲RBO)
    它根據指定的規則順序,對指定的表進行執行計劃的選擇。它着一套嚴格的使用規則,只要你按照它去寫SQL語句,不管數據表中的
內容怎樣,也不會影響到你的「執行計劃」,也就是說RB對數據不「敏感」。要求開發人員瞭解RBO的各項細則。在ORACLE 
10g中徹底被CBO取代。

基於代價的優化方式(Cost-Based Optimization,簡稱爲CBO)。
    CBO是一種比RBO更加合理、可靠的優化器,它是從ORACLE 8中開始引入,在ORACLE10g中徹底取代RBO。CBO是計算各類可能「執行
計劃」的「代價」,即COST,從中選用COST最低的執行方案,做爲實際運行方案。它依賴數據庫對象的統計信息,統計信息的準確與否會影響C
BO作出最優的選擇。若是對一次執行SQL時發現涉及對象(表、索引等)沒有被分析、統計過,那麼ORACLE會採用一種叫作動態採樣的技術,
動態的收集表和索引上的一些數據信息。
二、Oracle索引
Oracle索引是一種供服務器在表中快速查找一個行的數據庫結構。合理使用索引可以大大提升數據庫的運行效率。
在Oracle中,索引是一種供服務器在表中快速查找一個行的數據庫結構。在數據庫中創建索引主要有如下做用。
(1)快速存取數據。
(2)既能夠改善數據庫性能,又能夠保證列值的惟一性。
(3)實現表與表之間的參照完整性
(4)在使用order by、group by子句進行數據檢索時,利用索引能夠減小排序和分組的時間。
  三、優化方向
a、去掉沒必要要的大型表的全表掃描
b、去掉沒必要要的大型表的全表掃描
c、緩存小型表的全表掃描
d、檢驗優化索引的使用
e、檢驗優化的鏈接技術
f、儘量減小執行計劃的Cost

四、具體優化方法

一、查詢條件(where後面的子句)優化
避免全表掃描,應考慮在where及order by等列上創建索引,不然將致使進行全表掃描。。

避免在where子句中對字段進行null值判斷,不然將致使放棄使用索引而進行全表掃描。

避免在where子句中使用!=或<>操做符,不然將致使放棄使用索引而進行全表掃描。

避免用or鏈接條件,若是有部分字段存在索引,部分不存在索引,則將致使放棄使用索引而進行全表掃描,建議使用union all代替。

慎用in 和 not in 也要慎用,不然會致使全表掃描。
     使用exists替換in問題
        子查詢結果集小,用IN
        外表小,子查詢表大,用EXISTS
    建議實際選取哪一個能夠對比兩個sql的執行計劃

應儘可能避免在 where 子句中對字段進行表達式操做,這將致使引擎放棄使用索引而進行全表掃描。如: 
SELECT ID FROM T WHERE NUM / 2 = 100
優化爲:
SELECT ID FROM T WHERE NUM = 100 * 2

應儘可能避免在where子句中對字段進行函數函數、算術運算或其餘表達式運算操做,不然將致使放棄使用索引而進行全表掃描。如:
-- NAME以ABC開頭的ID
SELECT ID FROM T WHERE SUBSTRING(NAME, 1, 3) = ’ABC’ 
--2005-11-30’生成的id
SELECT ID FROM T WHERE DATEDIFF(DAY, CREATEDATE, ’2005 - 11 - 30′) = 0
應改成:
SELECT ID FROM T WHERE NAME LIKE 'abc%'
SELECT ID FROM T WHERE CREATEDATE >= '2005-11-30' AND CREATEDATE < '2005-12-1'
二、對結果進行優化
Update 語句,若是隻更改一、2個字段,不要Update所有字段,不然頻繁調用會引發明顯的性能消耗,同時帶來大量日誌。

對於多張大數據量(這裏幾百條就算大了)的表JOIN,要先分頁再JOIN,不然邏輯讀會很高,性能不好。

select count(*) from table;這樣不帶任何條件的count會引發全表掃描,而且沒有任何業務意義,是必定要杜絕的。

儘可能避免向客戶端返回大數據量,若數據量過大,應該考慮是否使用分頁
三、其餘優化
索引並非越多越好,索引當然能夠提升相應的 select 的效率,但同時也下降了 insert 及 update 的效率,由於 insert 或 
update 時有可能會重建索引,因此怎樣建索引須要慎重考慮,視具體狀況而定。一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到
的列上建的索引是否有必要。

應儘量的避免更新彙集索引(clustered)數據列,由於彙集索引數據列的順序就是表記錄的物理存儲順序,一旦該列值改變將致使整個表記錄的
順序的調整,會耗費至關大的資源。若應用系統須要頻繁更新集索引數據列,那麼須要考慮是否應將該索引建爲彙集索引

儘可能使用數字型字段,若只含數值信息的字段儘可能不要設計爲字符型,這會下降查詢和鏈接的性能,並會增長存儲開銷。這是由於引擎在處理查詢
和鏈接時會逐個比較字符串中每個字符,而對於數字型而言只須要比較一次就夠了。

儘可能使用表變量來代替臨時表。若是表變量包含大量數據,請注意索引很是有限(只有主鍵索引)。

避免頻繁建立和刪除臨時表,以減小系統表資源的消耗。臨時表並非不可以使用,適當地使用它們可使某些例程更有效,例如,當須要重複引用
大型表或經常使用表中的某個數據集時。可是,對於一次性事件, 最好使用導出表。

在新建臨時表時,若是一次性插入數據量很大,那麼可使用 select into 代替 create table,避免形成大量 
log,以提升速度;若是數據量不大,爲了緩和系統表的資源,應先create table,而後insert。

若是使用到了臨時表,在存儲過程的最後務必將全部的臨時表顯式刪除,先 truncate table ,而後 drop table 
,這樣能夠避免系統表的較長時間鎖定。

儘可能避免使用遊標,由於遊標的效率較差,若是遊標操做的數據超過1萬行,那麼就應該考慮改寫。

使用基於遊標的方法或臨時表方法以前,應先尋找基於集的解決方案來解決問題,基於集的方法一般更有效。
與臨時表同樣,遊標並非不可以使用。對小型數據集使用 FAST_FORWARD 遊標一般要優於其餘逐行處理方法,尤爲是在必須引用幾個表才能得到所
需的數據時。在結果集中包括「合計」的例程一般要比使用遊標執行的速度快。若是開發時 
間容許,基於遊標的方法和基於集的方法均可以嘗試一下,看哪種方法的效果更好。

在全部的存儲過程和觸發器的開始處設置 SET NOCOUNT ON ,在結束時設置 SET NOCOUNT OFF 
。無需在執行存儲過程和觸發器的每一個語句後向客戶端發送 DONE_IN_PROC 消息。

儘可能避免大事務操做,提升系統併發能力。
相關文章
相關標籤/搜索