ORACLE 多表查詢優化收集整理

  搞Web兩年多了,從大學正式開始作項目算起,本身也接手了三四個項目了,積累了一些經驗,最感謝的是大四的時候個人老師,很是信任我,讓我徹底負責一個項目,全套的,需求,設計,測試,發佈等,所有我負責,當初很瘋狂的說,整日整日的熬夜,如今工做大半年了,天天都循序漸進的,天天過着悠哉的日子,很思念大學時候瘋狂的日子,那些CD的日子一去不復返了。sql

  如今也沒方向了,在社區裏看到有人發帖也說了這個事情,你們都很糾結啊,因此以爲從根基開始,先從整理本身D盤那些收集的以及之前記錄的一些心得體會。數據庫

  搞WEB的離不開數據庫,在一個層面上,對數據庫的熟練程度決定了不少的事情,大學時期的SqlServer Mysql 到如今用的Sysbase ORACLE 我的比較喜歡ORACLE 它的gui工具比較完善,比較好用,並且好像免費,只是服務難免費。編程

  本文就你們都糾結的ORACLE多表查詢的性能問題給出一系列個優化方法,那這些都是項目中長期用到的,因此很熟,很熟,已經成爲習慣了。緩存

   ORACLE有個高速緩衝的概念,這個高速緩衝呢就是存放執行過的SQL語句,那oracle在執行sql語句的時候要作不少工做,例如解析sql語句,估算索引利用率,綁定變量,讀取數據塊等等這些操做。假設高速緩衝裏已經存儲了執行過的sql語句,那就直接匹配執行了,少了步驟,天然就快了,可是通過測試會發現高速緩衝只對簡單的表起做用,多表的狀況小徹底沒有效果啊,例如在查詢單表的時候那叫一個快,可是假設鏈接多個表,就龜速了。oracle

    最重要一點,ORACLE的高速緩衝是全字符匹配的,什麼意思呢,看下面三個select工具

--No.1
select * from tableA;
--No.2
select * From tableA;
--No.3
select   * from tableA;

這三個語句乍一看是同樣的,可是高速緩存是不認的,是全字符匹配的,索引在高速緩存裏會存儲三條不一樣的語句,說道這裏,又引出一個習慣,就是要保持良好的編程習慣,這個很重要啊。性能

 ORACLE的多表優化我積累了一些,都是經常使用的,介紹下測試

第一點呢是From 子句後面的 表順序有講究大數據

   先說爲啥,ORACLE在解析sql語句的時候對From子句後面的表名是從右往左解析的,是先掃描最右邊的表,而後在掃描左邊的表,而後用左邊的表匹配數據,匹配成功後就合併。優化

   因此,在對多表查詢中,必定要把小表寫在最右邊,爲何本身想一想就明白了。例以下面的兩個語句:

--No.1  tableA 100w條記錄  tableB 1w條記錄 執行速度 十秒級
select count(*) from tableA,tableB;
  
--No.2  執行速度百秒級甚至更高
select count(*) from tableB,tableA;

這個估計不少人都知道,可是要確認很是有用。

還有一種是三張表的查詢,例如

select count(1) from tableA a,tableB b ,tableC c where a.id=b.id and a.id=c.id;

上面種 tableA 就稱爲交叉表,根據oracle對From子句從右向左的掃描方式,應該把交叉表放在最末尾,而後纔是最小表,因此上面的應該這樣寫

--tableA a 交叉表 
--tabelB b 100w
--tableC c 1w
select count(1) from tableB b ,tableC c ,tableA a where a.id=b.id and a.id=c.id;

這種寫法對大數據量會很是有用,你們謹記,也是很經常使用的。

第二點呢是Where子句後面的條件過濾有講究,ORACLE對where子句後面的條件過濾是自下向上,從右向左掃描的,因此和From子句同樣同樣的,把過濾條件排個序,按過濾數據的大小,天然就是最少數據的那個條件寫在最下面,最右邊,依次類推,例如

--No.1 不可取 性能低下
select * from tableA a where 
a.id>500
and a.lx = '2b'
and a.id < 'select count(1) from tableA  where id=a.id '

--No.2 性能高
select * from tableA a where 
a.id < 'select count(1) from tableA  where id=a.id '
and a.id>500
and a.lx = '2b'

第三點呢估計搞數據庫的都知道啦,就是在select的時候少用*,多敲敲鍵盤,寫上字段名吧,由於ORACLE的查詢器會把*轉換爲表的所有列名,這個會浪費時間的,因此在大表中少用。

第四點呢就是要使用rowid 這個很好啊,能夠用來分頁,刪除查詢重複記錄,很強大的,給兩個例子:

--查找重複記錄
select * from  tableA  a where
 a.rowid> (
 select min(rowid) from tableB b where 
 a.column=b.column
 ) 
--刪除相同記錄
delete from  tableA  a where
 a.rowid> (
 select min(rowid) from tableB b where 
 a.column=b.column
 ) 

--分頁 start=10 limit=10
--end 爲 start + limit
select * from 
(
  select A.*,Rownum rn from 
    (select * from tableA order by id) A
  where rownum <= 20
) b wehre rn> 10  order by id desc 

/*解釋一下, 1.查詢要排列的表 A
             2.查詢A表的Rownum 找出小於end的數據 組成表B
             3.查詢B表經過rownum找出大於start的數據 完成
簡單的說先根據end值過濾數據,而後在根據start過濾數據
so 簡單的
*/

第五點是存儲過程當中須要注意的,多用commit了,既能夠釋放資源,可是要謹慎啊。

第六點是減小對數據庫表的查詢,這個很重要,能減小就減小,由於在執行語句的時候oracle會作不少初始工做。

第七點不要用in啦,用exists來代替咯,例如:

--NO.1  IN的寫法  
SELECT * FROM TABLEA A WHERE 
A.ID IN 
( SELECT ID FORM TABLEB B WHERE B.ID>1)

--NO.2 exists 寫法
SELECT * FROM TABLEA A WHERE
EXISTS (
SELECT 1 FROM TABLEB B WHERE A.ID=B.ID AND B.ID>1)

相同的還有使用not exists 代替 not in ,方法雷同啊,就不介紹了。

那還有一些簡單的方法,例如索引這些就比較簡單了,就不介紹了,就寫在這裏吧。

天天整理一點,說不定能夠找到方向啊,很迷茫啊,大俠們指點一下小弟啊,畢業才大半年就沒得方向了。

相關文章
相關標籤/搜索