學習筆記

          Simple is beautiful.

          導航

          <2007年5月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          統計

          公告

          ...

          常用鏈接

          留言簿(1)

          隨筆分類(2)

          隨筆檔案(56)

          Weblog

          搜索

          最新評論

          評論排行榜

          SQL語句性能調整

          SQL語句性能調整的目標是:
            去掉不必要的大表全表掃描---不必要的大表全表掃描會造成不必要的輸入輸出,而且還會拖垮整個數據庫;
            檢查優化索引的使用---這對于提高查詢速度來說非常重要
            檢查子查詢---考慮SQL子查詢是否可以用簡單連接的方式進行重新書寫;
            調整PCTFREE和PCTUSED等存儲參數優化插入、更新或者刪除等操作;
            考慮數據庫的優化器;
            考慮數據表的全表掃描和在多個CPU的情況下考慮并行查詢;
            一、 索引(INDEX)使用的問題
            1. 索引(INDEX),用還是不用?這是個的問題。
            是全表掃描還是索引范圍掃描主要考慮SQL的查詢速度問題。這里主要關心讀取的記錄的數目。根據DONALD K .BURLESON的說法,使用索引范圍掃描的原則是:
            對于數據有原始排序的表,讀取少于表記錄數40%的查詢應該使用索引范圍掃描。對讀取多于表記錄數40%的查詢應全表掃描。
          對于未排序的表,讀取少于表記錄數7%的查詢應該使用索引范圍掃描,反之,對讀取多于表記錄數7%的查詢應全表掃描。
            注:在不同的書中,對是否使用索引的讀取記錄的百分比值不太一致,基本上是一個經驗值,但是讀取記錄的百分比越低,使用索引越有效。
            2. 如果列上有建索引,什么SQL查詢是有用索引(INDEX)的?什么SQL查詢是沒有用索引(INDEX)的?
            存在下面情況的SQL,不會用到索引:
            存在數據類型隱形轉換的,如:
            select * from staff_member where staff_id=’123’;
            列上有數學運算的,如:
            select * from staff_member where salary*2<10000>
            使用不等于(<> )運算的,如:
            select * from staff_member where dept_no<>2001;
            使用substr字符串函數的,如:
            select * from staff_member where substr(last_name,1,4)=’FRED’;
            ‘%’通配符在第一個字符的,如:
            select * from staff_member where first_name like ‘%DON’;
            字符串連接(||)的,如:
            select * from staff_member where first_name||’’=’DONALD’
            3. 函數的索引
            日期類型也是很容易用到的,而且在SQL語句中會使用to_char函數以查詢具體的的范圍日期。如:select * from staff_member where TO_CHAR(birth_day,’YYYY’)=’2003’; 我們可以建立基于函數的索引如:CREATE INDEX Ind_emp_birth ON staff_member (to_char((birth_day,’YYYY’));
            二、 SQL語句排序優化
            1. 排序發生的情況:
            SQL中包含group by 子句
            SQL 中包含order by 子句
            SQL 中包含 distinct 子句
            SQL 中包含 minus 或 union操作
            創建索引時
            2. 排序在內存還是在磁盤中進行?
            在內存執行的排序速度要比在磁盤執行的排序速度快14000倍。如果是專用連接,排序內存根據INIT.ORA的sort_area_size進行分配,如果是多線程服務連接,排序內存根據large_pool_size進行分配。
            sort_area_size的增大可以減少磁盤排序,但是過大將使ORACLE性能降低,因為所用的連接回話都會分配到一個sort_area_size大小的內存,所以,為了提高有限的查詢速度,可能會浪費大量的內存。
            增加sort_multiblock_read_count的值使每次讀取更多的內容,減少運行次數,提高性能。

            三、SQL子查詢的調整
            1、理解關聯子查詢和非關聯子查詢。
            下面是一個非關聯子查詢:
            select staff_name from staff_member where staff_id
            in (select staff_id from staff_func);
            而下面是一個關聯子查詢:
            select staff_name from staff_member where staff_id in (select staff_id from staff_func where staff_member.staff_id=staff_func.staff_id);
            以上返回的結果集是相同的,可是它們的執行開銷是不同的:
            非關聯查詢的開銷——非關聯查詢時子查詢只會執行一次,而且結果是排序好的,并保存在一個ORACLE的臨時段中,其中的每一個記錄在返回時都會被父查詢所引用。在子查詢返回大量的記錄的情況下,將這些結果集排序,以及將臨時數據段進行排序會增加大量的系統開銷。
            關聯查詢的開銷——對返回到父查詢的的記錄來說,子查詢會每行執行一次。因此,我們必須保證任何可能的時候子查詢用到索引。
            2、XISTS子句和IN子句
            帶IN的關聯子查詢是多余的,因為IN子句和子查詢中相關的操作的功能是一樣的。如:
            select staff_name from staff_member where staff_id in (select staff_id from staff_func where staff_member.staff_id=staff_func.staff_id);
            為非關聯子查詢指定EXISTS子句是不適當的,因為這樣會產生笛卡乘積。如:
            select staff_name from staff_member where staff_id
            Exists (select staff_id from staff_func);
            盡量不要使用NOT IN子句。使用MINUS 子句都比NOT IN 子句快,雖然使用MINUS子句要進行兩次查詢:
            select staff_name from staff_member where staff_id in (select staff_id from staff_member MINUS select staff_id from staff_func where func_id like ‘81%’);
            3、 任何可能的時候,用標準連接或內嵌視圖改寫子查詢。
            四、更新、插入、以及刪除等DML語句的調整
            1、DML語句是指用來執行更新、插入、以及刪除等操作類型的語句。這些語句在結構上是很簡單的,可調整的余地較小。性能低下的情況有:
            插入緩慢并占有過多的I/O資源——這種情況主要是空閑列表(free list)中的數據塊的空間過小,僅容的下較少的記錄。
            更新緩慢——這種情況主要是UPDATE操作擴展了一個VARCHAR2類型的列,而ORACLE被強制將內容遷移到其他數據塊時。
            刪除緩慢——這種情況主要是記錄被刪除,ORACLE必須將數據塊重新放置到空閑列表(free list)時。
            因此,對DML進行調整,主要時利用對象存儲參數和SQL之間的關系進行調整。
          2、 CTFREE存儲參數
            PCTFREE存儲參數告訴ORACLE什么時候應該將數據塊從對象的空閑列表中移出。ORACLE的默認參數是PCTFREE=10;也就是說,一旦一個INSERT操作使得數據塊的90%被使用,這個數據塊就從空閑列表(free list)中移出。
            PCTUSED存儲參數
            PCTUSED存儲參數告訴ORACLE什么時候將以前滿的數據塊加到空閑列表中。當記錄從數據表中刪除時,數據庫的數據塊就有空間接受新的記錄,但只有當填充的空間降到PCTUSED值以下時,該數據塊才被連接到空閑列表中,才可以往其中插入數據。PCTUSED的默認值是PCTUSED=40。
            存儲參數規則小結
           ?。?)PCTUSED較高意味著相對較滿的數據塊會被放置到空閑列表中,從而有效的重復使用數據塊的空間,但會導致I/O消耗。PCTUSED低意味著在一個數據塊快空的時候才被放置到空閑列表中,數據塊一次能接受很多的記錄,因此可以減少I/O消耗,提高性能。
           ?。?)PCTFREE的值較大意味著數據塊沒有被利用多少就從空閑列表中斷開連接,不利于數據塊的充分使用。PCTFREE過小的結果是,在更新時可能會出現數據記錄遷移(Migration)的情況。(注:數據記錄遷移(Migration)是指記錄在是UPDATE操作擴展了一個VARCHAR2類型的列或BLOB列后,PCTFREE參數所指定的空間不夠擴展,從而記錄被ORACLE強制遷移到新的數據塊,發生這種情況將較嚴重的影響ORACLE的性能,出現更新緩慢)。
            (3)在批量的插入、刪除或者更新操作之前,先刪除該表上的索引,在操作完畢之后在重新建立,這樣有助于提高批量操作的整體速度,并且保證B樹索引在操作之后有良好的性能。
            3、 同優化器下的調整;
            基于成本優化器(CBO):
            (1)ORACLE 8i 以上版本更多地使用成本優化器,因為它更加智能;
           ?。?)通過optimizer_mode=all_rows 或 first_rows來選擇CBO;通過alter session set optimizer_goal=all_rows 或 first_rows來選擇CBO;通過添加hint來選擇CBO;
           ?。?)使用基于成本優化的一個關鍵是:存在表和索引的統計資料。通過analyze table 獲得表的統計資料;通過analyze index獲得索引的統計資料。
            (4)對于超過5個表的連接的查詢,建議不要使用成本優化器,而是在SQL語句中通過添加/* + rule */提示或者通過指定的執行計劃來避免可能會在20分鐘以上的SQL解析時間。
            基于規則優化器(RBO):
           ?。?)ORACLE 8i以及ORACLE的以前版本主要用(RBO),并且比較有效;
            (2)通過optimizer_mode=rule來選擇RBO;通過alter session set optimizer_goal=rule來選擇RBO; 通過添加/* + rule */來選擇RBO;
           ?。?)在RBO中,from 子句的表的順序決定表的連接順序。From 子句的最后一個表是驅動表,這個表應該是最小的表。
           ?。?)限定性最強的布爾表達式放在最底層。

            4、跟蹤、優化SQL語句的方法
            保證在實例級將TIMED_STATISTICS設置為TRUE(在 INIT.ORA中永久的設置它或執行 ALTER SYSTEM 命令臨時設置它);
            保證將MAX_DUMP_FILE_SIZE設置的較高。此參數控制跟蹤文件的大小。
            決定USER_DUMP_DEST所指向的位置,并保證有足夠的磁盤空間。這是放置跟蹤文件的位置。
            在應用系統運行時,打開所懷疑的回話的SQL_TRACE.(在 INIT.ORA中通過SQL_TRACE=TRUE永久的設置對所有的回話進行跟蹤或通過使用系統包DBMS_SYSTEM.set_sql_trace_in_session(sid,serial,true);命令臨時設置它)
            執行業務相關操作;
            設置跟蹤結束(DBMS_SYSTEM.set_sql_trace_in_session(sid,serial,false),如果沒有該步驟,可能跟蹤文件中的信息不全,因為可能有一部分還在緩存中);
            定位跟蹤文件;
            對步驟6的跟蹤文件進行TKPROF,生成報告文件;
            研究此報告文件,可以看到CPU、DISK、 QUERY、 COUNT等參數和execution plan(執行計劃),優化開銷最大的SQL;
            重復執行步驟4)~9)直到達到所需的性能目標;

          posted on 2007-05-21 22:49 Ecko 閱讀(289) 評論(0)  編輯  收藏


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


          網站導航:
           
          主站蜘蛛池模板: 海安县| 招远市| 鲁山县| 乌苏市| 安溪县| 宁津县| 东乡县| 云梦县| 景德镇市| 海丰县| 沅江市| 云安县| 章丘市| 怀安县| 和田县| 金寨县| 清涧县| 从化市| 依安县| 南召县| 东城区| 泗洪县| 岑巩县| 普兰店市| 剑河县| 五峰| 双辽市| 遂昌县| 新安县| 潞西市| 永福县| 永宁县| 临洮县| 泸定县| 遵义市| 桂东县| 宁安市| 密云县| 嘉黎县| 修水县| 军事|