Oracle初級性能優化總結

前言數據庫

  關於對Oracle數據庫查詢性能優化的一個簡要的總結。 歷來數據庫優化都是一項艱鉅的任務。對於大數據量,訪問頻繁的系統,優化工做顯得尤其重要。因爲Oracle系統的靈活性、複雜性、性能問題的緣由多樣性以及Oralce數據庫的動態特性,優化成爲Oracle數據庫管理中最困難的領域。做爲一個對數據庫瞭解很少的程序猿,我也只能從最基本的開始着手,慢慢來學習掌握Oracle的基礎吧。性能優化

示例性能

一、避免使用select *學習

  當你想在select字句中列出全部的column時,使用「select *」是一個方便的方法。不幸的是,這是一個低效的方法。實際上,Oracle在解析的過程當中,會將‘*’依次轉換成全部的列名,這個工做是經過查詢數據字典完成的,這意味着將耗費更多的時間。大數據

---糟糕的查詢
select * from Table_Name1 
---較好的查詢
select columnname1,columnname2,columnname3 from Table_Name1

 

二、使用表的別名
當在SQL語句中鏈接多個表時,請使用表的別名並把別名前綴於每一個column上。這樣一來,就能夠減小解析的時間並減小那些由column歧義引發的語法錯誤。
column歧義指的是因爲SQL中不一樣的表具備相同的column名,當SQL語句中出現這個column時,SQL解析器沒法判斷這個column的歸屬。優化

---糟糕的查詢
select columnname from Table_Name1 t1,Table_Name2
---較好的查詢
select t1.columnname from Table_Name1 t1,Table_Name2

 

三、用Exists 替代 in
在許多基於基礎表的查詢中,爲了知足一個條件,每每須要對另外一個表進行聯接。在這種狀況下,使用exists(或not exists)一般將提升查詢的效率。spa

例子:從小賣部買東西(商品),假若有個庫存表Table1,買東西出庫表Table2.查找庫存中的商品,是否有被賣出的,有的話就輸出庫存信息。code

--糟糕的查詢
SELECT column_name
FROM table_name1
WHERE column_name IN
( SELECT column_name
  FROM table_name2)
---較好的查詢
SELECT column_name
FROM table_name1 outer
WHERE EXISTS
  (SELECT 1
  FROM table_name2 inner
  WHERE inner.column_name = outer.column_name)

 

四、用not exists 替代 not in
在子查詢中,not in子句將執行一個內部的排序和合並。不管在那種狀況下,not in 都是低效的(由於它對子查詢中的表執行了一個全表遍歷)。爲了不使用 not in ,咱們能夠把它改寫成外鏈接(outer join)或 not exists。blog

---糟糕的查詢
select columnname,columnname1 from Table_Name1 
where id not in(select id from Table_Name2 where name='A')
---較好的查詢
select columnname,columnname1 from Table_Name1 t1,Table_Name2 t2 
where t1.id=t2.id
and t2.name<>'A'
---更好的查詢
select columnname,columnname1 from Table_Name1 t1
where not exists(select 1 from Table_Name2 t2
where t2.id=t1.id
and t2.name='A')

 

五、用錶鏈接替換Exists
一般來講,採用錶鏈接的方式比Exists更有效率。
可是不少狀況下咱們沒法將Exists改編爲鏈接。排序

---糟糕的查詢
select columnname,columnname1 from Table_Name1 t1
where not exists(select 1 from Table_Name2 t2
where t2.id=t1.id
and t2.name='A')
---較好的查詢
select columnname,columnname1 
from Table_Name1 t1
join Table_Name2 t2 on t1.id=t2.id
where t2.name='A'

 

六、用exists替換distinct

當提交一個包含一對多表信息(好比部門表和僱員表)的查詢時,避免在select字句中使用distinct。通常能夠考慮用Exists替換。Exists使查詢更爲迅速,由於RDBMS核心模塊將在子查詢的條件一旦知足後,馬上返回結果。

例子:從小賣部買東西(商品),假若有個庫存表Table_Name1,買東西出庫表Table_Name2.查找庫存中的商品,是否有被賣出的,有的話就輸出庫存信息。

--糟糕的查詢
SELECT DISTINCT t1.column_name
FROM table_name1 t1, table_name2 t2
WHERE t1.column_name = t2.column_name;
---較好的查詢
SELECT column_name
FROM table_name1 outer
WHERE EXISTS
  (SELECT 1
  FROM table_name2 inner
  WHERE inner.column_name = outer.column_name)

 

七、用>=替換>
若是id上有一個索引,則:

///糟糕的查詢
select * from EMP where id>3;
//較好的查詢
select * from EMP where id>=4;

二者的區別在於,後者將直接跳轉到第一個id等於4的記錄而前者將首先定位到id=3的記錄而且向前掃描到第一個id大於3的記錄。

 

八、用UNION替換OR
一般狀況下,用UNION替換where字句中的OR將會起到較好的效果。對索引列使用OR將形成全表掃描。注意,以上規則只針對多個索引列有效。查詢效率可能會由於沒有選擇OR而下降。

---糟糕的查詢
select id,name,reg where Table_Name1 where id=10 or reg='A'
---較好的查詢
 select id,name,reg from Table_Name1 t1 where t1.id=10
 union
 select id,name,reg from Table_Name2 t2 where t2.reg='A'

固然以上要基於id列和reg列都是索引列。

 

九、用UNION-ALL 替換UNION
當SQL語句須要UNION兩個查詢結果集合時,這兩個結果集合會以UNION-ALL的方式被合併,而後在輸出最終結果前進行排序,並將重複記錄過濾掉。
若是用UNION ALL替代UNION,這樣排序就不是必要了,效率會所以獲得提升。
須要注意的是,UNION ALL將重複輸出兩個結果集合中相同記錄,所以仍是要從業務需求 分析使用UNION ALL的可行性。

---糟糕的查詢,須要進行排序
 select id,name,reg from Table_Name1 t1 where t1.id=10
 union
 select id,name,reg from Table_Name2 t2 where t2.id=10
---較好的查詢,不須要排序
 select id,name,reg from Table_Name1 t1 where t1.id=10
 union  all
 select id,name,reg from Table_Name2 t2 where t2.id=10

考慮的時候必定也要基於業務的需求進行取捨。

 

十、避免在索引列上使用IS NULL和IS NOT NULL
對於單列索引,若是列包含空值,索引中將不存在此記錄。
對於複合索引,若是每一個列都爲空,索引中一樣不存在此記錄。若是至少有一個列不爲空。則記錄存在於索引中。
由於空值不存在於索引列中,因此where子句中對索引列進行空值比較將使Oracle停用該索引。

---糟糕的查詢
 select id,name,reg from Table_Name1 t1 where t1.id is not null
---較好的查詢
select id,name,reg from Table_Name2 t2 where t2.id>=10

前提仍是id列是索引列

總結

   本節暫時總結到這裏,以後繼續進行總結,感受仍是頗有用的,而後在平常的工做中加以實踐,應該對本身的能力有所改善。上面總結的都是常規的作法,固然具體優化還要根據具體的環境進行處理,處理方式複雜多變,但萬變不離其宗。若有錯誤,請及時通知加以更正,謝謝。

相關文章
相關標籤/搜索