人在江湖

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            82 Posts :: 10 Stories :: 169 Comments :: 0 Trackbacks
          這篇文字主要討論sql的一般編寫原則。下一篇討論根據執行計劃進行調優的話題。
          網上這類文章很多,但往往只是給出結論,比如,這樣寫sql會比那樣寫sql效率更高。閱讀者如果打算打開數據庫自己做一遍實驗,看看效率差異到底有多少,需要自己造數據,還是比較麻煩。這篇文字會把DDL和DML以及sql的執行時間都寫出來,一方面給一個更直觀的印象,另一方面方便閱讀者自己實驗。
          以Oracle為實驗用數據庫,使用著名的emp表。安裝oracle數據庫之后,scott用戶的密碼是tiger. 在他的schema下有幾張sample表,很多sql教程都以這幾張表為基礎. 據說,熟悉oracle數據庫的人提到smith這個人名,就能聯想起sample表中他的工作是clerk. emp表就是sample表之一。這張表原始數據只有14行,為了體現不同sql性能上的差異,我們需要多填充一些數據進去。作為填充數據的預備知識,我們可以看一下如何生成一系列從小到大的id:
          SELECT ROWNUM
          FROM DUAL
          CONNECT BY LEVEL < 10000;
          填充隨機數據可以借助于dbms_random包,不想覆蓋已有的表,所以新創建一個表結構基本一樣的: 
          create table emp_new
          as
          select level                                                          empno,
                 SYS.dbms_random.String('u', SYS.dbms_random.value(3,10))       ename,
                 SYS.dbms_random.String('u', SYS.dbms_random.value(3,9))        job,
                 round(SYS.dbms_random.value(1000,9999))                        mgr,
                 TO_DATE (   ROUND (DBMS_RANDOM.VALUE (128))
                              || '-'
                              || ROUND (DBMS_RANDOM.VALUE (112))
                              || '-'
                              || ROUND (DBMS_RANDOM.VALUE (19802012)),
                              'DD-MM-YYYY'
                             )                                                   hiredate,
                  round(SYS.dbms_random.value(300,9999))                         sal,
                  round(SYS.dbms_random.value(1,6)) * 100                        comm,
                  round(SYS.dbms_random.value(1,4)) * 10                         deptno
           FROM DUAL
          CONNECT BY LEVEL < 1000000;

          這里有一個局限,原本的emp表mgr列reference empno列。上面新創建的emp_new中失去了這個constraint. 這點可以從Oracle SQL Developer中看到。
          emp表:
          with_constrant.png
          emp_new表:
          no_constrant.png
          下面就開始測試sql了:
          1. 先比較一下加primary key前后的結果:
          select * from emp_new where empno=1;
          加primary key constraint之前運行0.023秒。 加了primary key constraint之后0.001秒。加primary key constraint在100萬條數據上大約花費4秒鐘。
          2. where子句 vs. having子句
          select deptno, avg(sal) from emp_new group by deptno having deptno != 10 and deptno != 20;
          0.24秒
          select deptno, avg(sal) from emp_new where deptno != 10 and deptno != 20 group by deptno ;
          0.16秒
          所以having中的條件一般用于對一些集合函數的比較,如count()等,除此之外,一般條件應該寫在where子句中。

          3. 減少對表的查詢
          update emp_new set sal=(select max(sal) from emp_new), comm=(select max(comm) from emp_new) where empno=1237;
          0.11秒左右
          update emp_new set (sal, comm) =(select max(sal), max(comm) from emp_new) where empno=1224;
          0.07秒到0.08秒之間

          注意:以上三個測試都只fetch前50條數據。

          4. 傳說中用exists替代in通常可提高查詢效率, not exists 也比not in 快。
          先生成dept_new表:
          create table dept_new
          as
          select level                                                          deptno,
                 SYS.dbms_random.String(
          'u', SYS.dbms_random.value(3,10))       dname,
                 SYS.dbms_random.String(
          'u', SYS.dbms_random.value(3,9))        loc
          FROM DUAL
          CONNECT 
          BY LEVEL < 10000;
          實際測試中,無論是執行計劃還是實際測試的速度都是基本一致的。
          第一組
          select * from emp_new e where e.empno > 986000 and e.deptno in (select d.deptno from dept_new d where d.loc='AYDN') select * from emp_new e where empno > 986000 and exists (select * from dept_new d where d.deptno = e.deptno and d.loc='AYDN') 第二組 select e.empno from emp_new e where e.empno > 996000 and not exists (select 1 from dept_new d where d.deptno = e.deptno and loc like 'A%') select e.empno from emp_new e where e.empno > 996000 and e.deptno not in (select d.deptno from dept_new d where loc like 'A%')

          這篇文字主要參考兩篇文章:
          Oracle sql  性能優化調整: http://wenku.baidu.com/view/571cddd4195f312b3169a507 




          posted on 2013-03-31 21:49 人在江湖 閱讀(3140) 評論(0)  編輯  收藏 所屬分類: java
          主站蜘蛛池模板: 潍坊市| 新干县| 炎陵县| 建瓯市| 苏尼特右旗| 长武县| 通州市| 绥芬河市| 文登市| 开鲁县| 拜城县| 龙山县| 石台县| 榆中县| 汉川市| 高碑店市| 邛崃市| 二连浩特市| 定边县| 东辽县| 高陵县| 佛教| 宁阳县| 绵阳市| 康定县| 彩票| 额济纳旗| 双桥区| 桃江县| 华坪县| 仲巴县| 巴楚县| 沙湾县| 云龙县| 大英县| 奉新县| 杭锦旗| 扎囊县| 大冶市| 贺州市| 长子县|