Java,J2EE,Weblogic,Oracle

          java項目隨筆
          隨筆 - 90, 文章 - 6, 評論 - 61, 引用 - 0
          數據加載中……

          oracle 優化

          一、用索引提高效率
                  索引是表的一個概念部分,用來提高檢索數據的效率,通過索引查詢數據比全表掃描要快.
                  ①避免在索引列上使用NOT 通常, 
                我們要避免在索引列上使用NOT, NOT會產生在和在索引列上使用函數相同的影響. ORACLE”遇到”NOT,他就會停止使用索引轉而執行全表掃描
                避免在索引列上使用計算.
          WHERE
          子句中,如果索引列是函數的一部分.優化器將不使用索引而使用全表掃描.
          舉例:
          低效:
          SELECT … FROM  DEPT  WHERE SAL * 12 > 25000;
          高效:
          SELECT … FROM DEPT WHERE SAL > 25000/12;

             ③ 用> 替代 >=
              高效:
          SELECT * FROM  EMP  WHERE  DEPTNO >=4
          低效:
          SELECT * FROM EMP WHERE DEPTNO >3
                ④UNION替換OR (適用于索引列)
          通常情況下, UNION替換WHERE子句中的OR將會起到較好的效果. 對索引列使用OR將造成全表掃描. 注意, 以上規則只針對多個索引列有效. 如果有column沒有被索引, 查詢效率可能會因為你沒有選擇OR而降低. 在下面的例子中, LOC_ID REGION上都建有索引.
          高效:
          SELECT LOC_ID , LOC_DESC , REGION
          FROM LOCATION
          WHERE LOC_ID = 10
          UNION
          SELECT LOC_ID , LOC_DESC , REGION
          FROM LOCATION
          WHERE REGION = “MELBOURNE”
          低效:
          SELECT LOC_ID , LOC_DESC , REGION
          FROM LOCATION
          WHERE LOC_ID = 10 OR REGION = “MELBOURNE”
          如果你堅持要用OR, 那就需要返回記錄最少的索引列寫在最前面.

                ⑤避免在索引列上使用IS NULL和IS NOT NULL
          避免在索引中使用任何可以為空的列,ORACLE將無法使用該索引.對于單列索引,如果列包含空值,索引中將不存在此記錄. 對于復合索引,如果每個列都為空,索引中同樣不存在此記錄. 如果至少有一個列不為空,則記錄存在于索引中.舉例: 如果唯一性索引建立在表的A列和B列上, 并且表中存在一條記錄的A,B值為(123,null) , ORACLE將不接受下一條具有相同A,B值(123,null)的記錄(插入). 然而如果所有的索引列都為空,ORACLE將認為整個鍵值為空而空不等于空. 因此你可以插入1000 條具有相同鍵值的記錄,當然它們都是空! 因為空值不存在于索引列中,所以WHERE子句中對索引列進行空值比較將使ORACLE停用該索引.
          低效: (索引失效)
          SELECT … FROM  DEPARTMENT  WHERE  DEPT_CODE IS NOT NULL;
          高效: (索引有效)
          SELECT … FROM  DEPARTMENT  WHERE  DEPT_CODE >=0;

              ⑥總是使用索引的第一個列:
          如果索引是建立在多個列上, 只有在它的第一個列(leading column)where子句引用時,優化器才會選擇使用該索引. 這也是一條簡單而重要的規則,當僅引用索引的第二個列時,優化器使用了全表掃描而忽略了索引

              ⑦ 避免改變索引列的類型.:
          當比較不同數據類型的數據時, ORACLE自動對列進行簡單的類型轉換.
          假設 EMPNO是一個數值類型的索引列.
          SELECT …  FROM EMP  WHERE  EMPNO = ‘123'
          實際上,經過ORACLE類型轉換, 語句轉化為:
          SELECT …  FROM EMP  WHERE  EMPNO = TO_NUMBER(‘123')
          幸運的是,類型轉換沒有發生在索引列上,索引的用途沒有被改變.
          現在,假設EMP_TYPE是一個字符類型的索引列.
          SELECT …  FROM EMP  WHERE EMP_TYPE = 123
          這個語句被ORACLE轉換為:
          SELECT …  FROM EMP  WHERETO_NUMBER(EMP_TYPE)=123
          因為內部發生的類型轉換, 這個索引將不會被用到! 為了避免ORACLE對你的SQL進行隱式的類型轉換, 最好把類型轉換用顯式表現出來. 注意當字符和數值比較時, ORACLE會優先轉換數值類型到字符類型
                    
           


          二、選擇最有效率的表名順序(只在基于規則的優化器中有效)
                ORACLE的解析器按照從右到左的順序處理FROM子句中的表名,因此FROM子句中寫在最后的表(基礎表 driving table)將被最先處理.
                例如:

          表 TAB1 16,384 條記錄

          表 TAB2 1 條記錄


          選擇TAB2作為基礎表 (最好的方法)

          select count(*) from tab1,tab2 執行時間0.96秒


          選擇TAB2作為基礎表 (不佳的方法)

          select count(*) from tab2,tab1 執行時間26.09秒


          如果有3個以上的表連接查詢, 那就需要選擇交叉表(intersection table)作為基礎表, 交叉表是指那個被其他表所引用的表.


          例如:

          EMP表描述了LOCATION表和CATEGORY表的交集.

          SELECT *

          FROM LOCATION L ,

          CATEGORY C,

          EMP E

          WHERE E.EMP_NO BETWEEN 1000 AND 2000

          AND E.CAT_NO = C.CAT_NO

          AND E.LOCN = L.LOCN


          將比下列SQL更有效率


          SELECT *

          FROM EMP E ,

          LOCATION L ,

          CATEGORY C

          WHERE E.CAT_NO = C.CAT_NO

          AND E.LOCN = L.LOCN

          AND E.EMP_NO BETWEEN 1000 AND 2000 

               

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

          (低效,執行時間156.3秒)

          SELECT …

          FROM EMP E

          WHERE SAL > 50000

          AND JOB = ‘MANAGER'

          AND 25 < (SELECT COUNT(*) FROM EMP

          WHERE MGR=E.EMPNO);


          (高效,執行時間10.6秒)

          SELECT …

          FROM EMP E

          WHERE 25 < (SELECT COUNT(*) FROM EMP

          WHERE MGR=E.EMPNO)

          AND SAL > 50000

          AND JOB = ‘MANAGER'; 

          四、 優化GROUP BY: 
           

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


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



          六、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); 


          七、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') 





                

          posted on 2008-05-31 13:29 龔椿深 閱讀(381) 評論(0)  編輯  收藏


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 图们市| 太谷县| 东山县| 工布江达县| 内乡县| 饶阳县| 延寿县| 勐海县| 枣庄市| 剑阁县| 岢岚县| 德阳市| 和田市| 灯塔市| 湄潭县| 于田县| 象山县| 乐安县| 德化县| 柘荣县| 进贤县| 肥西县| 霸州市| 馆陶县| 冀州市| 昌都县| 峡江县| 固安县| 云阳县| 娄底市| 安达市| 镇雄县| 调兵山市| 马关县| 乾安县| 青川县| 怀柔区| 宿松县| 尼木县| 高平市| 丽水市|