2018_04_16 數據庫SQL優化方案(一)

(1)選擇最有效率的表名順序

Oracle的解析器是按照從右到左的順序處理From子句中的表名,From子句中寫在最後的表(基礎表)將被最先處理,當From子句中包含多個表的情況時,應該選擇記錄條數最少的表作爲基礎表;如果是三個以上的表連接查詢,需要選擇交叉表作爲基礎表,交叉表就是被其他表所引用的表。

(2)Where子句中的連接順序

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

(3)Select子句中避免使用'*'

Oracle在解析過程中,會將'*'一次轉換成所有的列名。

(4)減少訪問數據庫的次數:

Oracle在內部執行了很多工作:解析SQL語句,估算索引的利用率,綁定變量,讀數據塊等。

(5)使用Decode函數來減少處理時間:

使用Decode函數可以避免重複掃描相同記錄或重複連接相同的表。

DECODE的語法:DECODE(value,if1,then1,if2,then2,if3,then3,...,else),表示如果value 等於if1時,DECODE函數的結果返回then1,...,如果不等於任何一個if值,則返回else。初看一下,DECODE 只能做等於測試,實際上我們通過一些函數或計算替代value,是可以使DECODE函數具備大於、小於或等於功能。

比較大小的函數:

  select decode(sign(變量1-變量2),-1,變量1,變量2) from dual; --取較小值

  sign()函數根據某個值是0、正數還是負數,分別返回0、1、-1

  例如:

  變量1=10,變量2=20

  則sign(變量1-變量2)返回-1,decode解碼結果爲“變量1”,達到了取較小值的目的。


(6)用Where子句替換Having子句


避免使用Having子句,HAVING 只會在檢索出所有記錄之後纔對結果集進行過濾。這個處理需要排序,總計等操作。如果能通過WHERE子句限制記錄的數目,那就能減少這方面的開銷。(非 oracle中)on、where、having這三個都可以加條件的子句中,on是最先執行,where次之,having最後,因爲on是先把不符合 條件的記錄過濾後才進行統計,它就可以減少中間運算要處理的數據,按理說應該速度是最快的,where也應該比having快點的,因爲它過濾數據後才進 行sum,在兩個表聯接時才用on的,所以在一個表的時候,就剩下where跟having比較了。在這單表查詢統計的情況下,如果要過濾的條件沒有涉及 到要計算字段,那它們的結果是一樣的,只是where可以使用rushmore技術,而having就不能,在速度上後者要慢如果要涉及到計算的字段,就 表示在沒計算之前,這個字段的值是不確定的,根據上篇寫的工作流程,where的作用時間是在計算之前就完成的,而having就是在計算後才起作用的, 所以在這種情況下,兩者的結果會不同。在多表聯接查詢時,on比where更早起作用。系統首先根據各個表之間的聯接條件,把多個表合成一個臨時表後,再 由where進行過濾,然後再計算,計算完後再由having進行過濾。由此可見,要想過濾條件起到正確的作用,首先要明白這個條件應該在什麼時候起作用,然後再決定放在那裏。


(7)減少對錶的查詢:

在含有子查詢的SQL語句中,要特別注意減少對錶的查詢

(8)使用表的別名(Alias): 

當在SQL語句中連接多個表時, 請使用表的別名並把別名前綴於每個Column上。這樣一來,就可以減少解析的時間並減少那些由Column歧義引起的語法錯誤。 

(9)用EXISTS替代IN、用NOT EXISTS替代NOT IN:
在許多基於基礎表的查詢中,爲了滿足一個條件,往往需要對另一個表進行聯接。在這種情況下,使用EXISTS(或NOT EXISTS)通常將提高查詢的效率。在子查詢中,NOT IN子句將執行一個內部的排序和合並。無論在哪種情況下,NOT IN都是最低效的 (因爲它對子查詢中的表執行了一個全表遍歷)。爲了避免使用NOT IN ,我們可以把它改寫成外連接(Outer Joins)或NOT EXISTS。

例子: 

(高效)SELECT * FROM EMP (基礎表) WHERE EMPNO > 0 AND EXISTS (SELECT ‘X' FROM DEPT WHERE DEPT.DEPTNO = EMP.DEPTNO AND LOC = ‘MELB')

(低 效)SELECT * FROM EMP (基礎表) WHERE EMPNO > 0 AND DEPTNO IN(SELECT DEPTNO FROM DEPT WHERE LOC = ‘MELB')

(10)用EXISTS替換DISTINCT:
當提交一個包含一對多表信息(比如部門表和僱員表)的查詢時,避免在SELECT子句中使用DISTINCT。一般可以考慮用EXIST替換, EXISTS 使查詢更爲迅速,因爲RDBMS核心模塊將在子查詢的條件一旦滿足後,立刻返回結果。例子:

(低效): SELECT DISTINCT DEPT_NO,DEPT_NAME FROM DEPT D , EMP E WHERE D.DEPT_NO = E.DEPT_NO 

(高效): SELECT DEPT_NO,DEPT_NAME FROM DEPT D WHERE EXISTS ( SELECT ‘X' FROM EMP E WHERE E.DEPT_NO = D.DEPT_NO);

(11)SQL語句用大寫的;因爲Oracle總是先解析SQL語句,把小寫的字母轉換成大寫的再執行。 

(12)避免在索引列上使用計算。WHERE子句中,如果索引列是函數的一部分。優化器將不使用索引而使用全表掃描。

(低 效): SELECT … FROM DEPT WHERE SAL * 12 > 25000; 
(高 效): SELECT … FROM DEPT WHERE SAL > 25000/12;

(13)用>=替代>:

高效:SELECT * FROM EMP WHERE DEPTNO >=4 

低效: SELECT * FROM EMP WHERE DEPTNO >3

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

(14)用IN來替換OR: 

(低 效):SELECT…. FROM LOCATION WHERE LOC_ID = 10 OR LOC_ID = 20 OR LOC_ID = 30

(高 效):SELECT… FROM LOCATION WHERE LOC_IN IN (10,20,30);

(15)優化GROUP BY:
提高GROUP BY 語句的效率,可以通過將不需要的記錄在GROUP BY 之前過濾掉。下面兩個查詢返回相同結果但第二個明顯就快了許多。
低效: SELECT JOB , AVG(SAL) FROM EMP GROUP BY JOB HAVING JOB = ‘PRESIDENT' OR JOB = ‘MANAGER' 
高效: SELECT JOB , AVG(SAL) FROM EMP WHERE JOB = ‘PRESIDENT' OR JOB = ‘MANAGER' GROUP BY JOB

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