oracle 開發誤區探索《一》

來源:互聯網
上載者:User
    環境:
sys@ORCL> select * from v$version where rownum=1;BANNER----------------------------------------------------------------Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prodsys@ORCL> !uname -aLinux localhost.localdomain 2.6.18-308.el5xen #1 SMP Fri Jan 27 17:59:00 EST 2012 i686 i686 i386 GNU/Linux
    ① 單列和複合列NOT IN 子查詢

    not in (........)裡面的null,如果存在null,則返回的絕對是空值。因為,in本是或的關係,加上not,則任何值和null,邏輯與,其結果都是空。

    測試:

    --Q1;單列not in子查詢有null分析

        hr@ORCL> drop table test1;
        hr@ORCL> drop table test2;
        hr@ORCL> create table test1 (id number);
       
        Table created.
       
        hr@ORCL> create table test2 (id number);
       
        Table created.
       
        hr@ORCL> insert into test1 values(1);
       
        1 row created.
       
        hr@ORCL> insert into test1 values(2);
       
        1 row created.
       
        hr@ORCL> insert into test2 values(null);
       
        1 row created.
       
        hr@ORCL> insert into test2 values(1);
       
        1 row created.
       
        hr@ORCL> commit;
       
        Commit complete.

      --需求:選出在test1、卻不在test2的記錄
      --單列、常見錯誤如下、沒有結果:

        hr@ORCL> select id from test1 where id not in (select id from test2);
       
        no rows selected

      --正確的寫法、常見的還是not exists

        hr@ORCL> select id from test1 where not exists (select 1 from test2 where test1.id=test2.id);
       
                ID
        ----------
                 2

    --Q2:複合列not in子查詢有null分析

        hr@ORCL> create table t1 (a number,b number);
       
        Table created.
       
        hr@ORCL> create table t2 (a number,b number);
       
        Table created.
       
        hr@ORCL> insert into t1 values(1,1);
       
        1 row created.
       
        hr@ORCL> insert into t1 values(1,2);
       
        1 row created.
       
        hr@ORCL> insert into t2 values(1,1);
       
        1 row created.
       
        hr@ORCL> insert into t2 values(null,2);
       
        1 row created.
       
        hr@ORCL> commit;
       
        Commit complete.

       --需求:選出在t1、卻不在t2的記錄
       --常見錯誤、和Q1一樣、沒有結果

        hr@ORCL> select * from t1 where (a,b) not in (select * from t2);   
       
        no rows selected
       
       
        --正確解法、常見的是not exists
        hr@ORCL> select * from t1 where not exists (select 1 from t2 where t1.a=t2.a and t1.b=t2.b);
       
                 A          B
        ---------- ----------
                 1          2
        --分析
          因為是複合列,相當於列的組合條件是or,根據NULL的比較和邏輯運算規則,OR條件有一個為TRUE則返回TRUE,全為FALSE則結果為FALSE,其他為UNKNOWN,
          比如(1,2) not in (null,2)則相當於1 <> null or 2 <> 2,那麼明顯返回的結果是UNKNOWN,所以不可能為真,不返回結果;
          但是(1,2) not in (null,3)相當於1 <> null or 2 <> 3,因為2<>3的已經是TRUE,所以條件為TRUE,返回結果;
          再做個簡單測試:
        hr@ORCL> select * from dual;
       
        D
        -
        X
        hr@ORCL> select * from dual where (1,1) not in ((null,2));
       
        D
        -
        X
        hr@ORCL> select * from dual where (1,1) not in ((null,1));
       
        no rows selected

 

 

    ② 消除隱式轉換

 

        在所有的auto trace分析中,都帶有Predicate information的關鍵字。Predicate information資訊有兩種取值:filter和access,一般索引讀和hash join,體現為access。
        關注Predicate information最重要的一點在於,查看是否發生了資料類型轉換。
        資料類型轉換,既產生了開銷,也影響索引的正常使用
        所以,任何時刻都不該在此處看到有資料類型的轉化
      --測試
      hr@ORCL> drop table t;
     
      Table dropped.
     
      hr@ORCL> create table t(col1 varchar2(20),col2 number);
     
      Table created.
     
      hr@ORCL> insert into t select rownum,rownum+1 from dual connect by level <=10000;
     
      10000 rows created.
     
      hr@ORCL> commit;
     
      Commit complete.
     
      hr@ORCL> create index idx_t on t(col1);
     
      Index created.
     
      hr@ORCL> set autot traceonly
      hr@ORCL> select * from t where col1=2 and col2=3;
     
     
      Execution Plan
      ----------------------------------------------------------
      Plan hash value: 1601196873
     
      --------------------------------------------------------------------------
      | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
      --------------------------------------------------------------------------
      |   0 | SELECT STATEMENT  |      |     1 |    25 |     6   (0)| 00:00:01 |
      |*  1 |  TABLE ACCESS FULL| T    |     1 |    25 |     6   (0)| 00:00:01 |
      --------------------------------------------------------------------------
     
      Predicate Information (identified by operation id):
      ---------------------------------------------------
     
         1 - filter("COL2"=3 AND TO_NUMBER("COL1")=2)
     
      Note
      -----
         - dynamic sampling used for this statement
     
     
      Statistics
      ----------------------------------------------------------
                5  recursive calls
                0  db block gets
               48  consistent gets
                0  physical reads
                0  redo size
              463  bytes sent via SQL*Net to client
              385  bytes received via SQL*Net from client
                2  SQL*Net roundtrips to/from client
                0  sorts (memory)
                0  sorts (disk)
                1  rows processed

      --通過statistics,可知:擷取1行產生48個邏輯讀,不符合擷取單行記錄小於5個邏輯讀的標準
      --在Predicate information資訊裡,我們發現此處存在TO_NUMBER("COL1")=2的類型轉換
      --查看t表的col1欄位類型為varchar2
      hr@ORCL> select * from t where col1='2' and col2=3;
     
      Execution Plan
      ----------------------------------------------------------
      Plan hash value: 1594971208
     
      -------------------------------------------------------------------------------------
      | Id  | Operation                   | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
      -------------------------------------------------------------------------------------
      |   0 | SELECT STATEMENT            |       |     1 |    25 |     2   (0)| 00:00:01 |
      |*  1 |  TABLE ACCESS BY INDEX ROWID| T     |     1 |    25 |     2   (0)| 00:00:01 |
      |*  2 |   INDEX RANGE SCAN          | IDX_T |     1 |       |     1   (0)| 00:00:01 |
      -------------------------------------------------------------------------------------
     
      Predicate Information (identified by operation id):
      ---------------------------------------------------
     
         1 - filter("COL2"=3)
         2 - access("COL1"='2')
     
      Note
      -----
         - dynamic sampling used for this statement
     
     
      Statistics
      ----------------------------------------------------------
                0  recursive calls
                0  db block gets
                4  consistent gets
                0  physical reads
                0  redo size
              463  bytes sent via SQL*Net to client
              385  bytes received via SQL*Net from client
                2  SQL*Net roundtrips to/from client
                0  sorts (memory)
                0  sorts (disk)
                1  rows processed
     
      --執行計畫由全表掃描變更為索引讀
      --在Predicate information,access("COL1"='2')表示用到了索引方式的訪問路徑
      --返回行與邏輯讀的比率也<5

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.