oracle 开发误区探索《一》

    环境:
sys@ORCL> select * from v$version where rownum=1;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod

sys@ORCL> !uname -a
Linux 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值