【Oracle】where条件执行顺序(上篇的问题延伸)

上篇问题链接:http://blog.itpub.net/30174570/viewspace-2148592/
问题:

  1. SYS@proc> create table t as select * from v$parameter;

  2. Table created.

  3. SYS@proc> select value from t where name='db_block_size' and to_number(value)=8192;

  4. VALUE
  5. --------------------------------------------------------------------------------
  6. 8192

  7. SYS@proc> select value from v$parameter where name='db_block_size' and to_number(value)=8192;
  8. select value from v$parameter where name='db_block_size' and to_number(value)=8192
  9.                                                              *
  10. ERROR at line 1:
  11. ORA-01722: invalid number
为什么语句“ select value from t where name = 'db_block_size' and to_number ( value ) = 8192 ; ”执行成功,换成v$parameter却报错。

实验研究过程:
  1. SYS@proc> set autotrace on
  2. SYS@proc> analyze table t compute statistics;

  3. Table analyzed.

  4. SYS@proc> select value from t where name='db_block_size' and to_number(value)=8192;

  5. VALUE
  6. --------------------------------------------------------------------------------
  7. 8192


  8. Execution Plan
  9. ----------------------------------------------------------
  10. Plan hash value: 1601196873

  11. --------------------------------------------------------------------------
  12. | Id | Operation         | Name  | Rows | Bytes | Cost (%CPU)| Time     |
  13. --------------------------------------------------------------------------
  14. |  0 | SELECT STATEMENT  |       |    1 |    26 |       4 (0)| 00:00:01 |
  15. |* 1 |  TABLE ACCESS FULL| T     |    1 |    26 |       4 (0)| 00:00:01 |
  16. --------------------------------------------------------------------------

  17. Predicate Information (identified by operation id):
  18. ---------------------------------------------------

  19.    1 - filter("NAME"='db_block_size' AND TO_NUMBER("VALUE")=8192)


  20. Statistics
  21. ----------------------------------------------------------
  22.      1 recursive calls
  23.      0 db block gets
  24.      9 consistent gets
  25.      0 physical reads
  26.      0 redo size
  27.    525 bytes sent via SQL*Net to client
  28.    523 bytes received via SQL*Net from client
  29.      2 SQL*Net roundtrips to/from client
  30.      0 sorts (memory)
  31.      0 sorts (disk)
  32.      1 rows processed
一开始看到这个执行计划很懵逼,完全搞不懂为什么能够执行成功,做10046,10053,改写sql加hint还是搞不懂。
最后猜想Oracle在 filter ( "NAME" = 'db_block_size' AND TO_NUMBER ( "VALUE" ) = 8192 ) 这个步骤,是先对数据做name='db_block_size'的过滤,在做to_number('value')=8192的过滤。
若是能将谓词信息改变成 filter (TO_NUMBER("VALUE") AND "NAME"='db_block_size'= 8192 ) 并且执行报错,那么猜想就是正确的。
尝试将sql语句的and条件调换位置" select value from t where to_number ( value )=8192 and name='db_block_size' ; ",不过还是和原来一样,这里省略步骤。

这里构造其他测试表:
  1. SYS@proc> create table a(id1 int,id2 int,id3 int,id4 int);

  2. Table created.

  3. SYS@proc> insert into a values(1,1,1,0);

  4. 1 row created.

  5. SYS@proc> commit;

  6. Commit complete.

  7. SYS@proc> select * from a;

  8.        ID1        ID2        ID3        ID4
  9. ---------- ---------- ---------- ----------
  10.          1          1          1          0
这里执行以下4条sql语句:
①Select 'ok' From aaa where id1/id2=1 and id3/id4=2;
②Select 'ok' From aaa where id1/id2=2 and id3/id4=2;
③Select 'ok' From aaa where id3/id4=2 and id1/id2=1;
④Select 'ok' From aaa where id3/id4=2 and id1/id2=2;
其中①和③,②和④只是where后条件位置互换而已。
查看执行结果:
  1. SYS@proc> Select 'ok' From aaa where id1/id2=1 and id3/id4=2;
  2. Select 'ok' From aaa where id1/id2=1 and id3/id4=2
  3.                                             *
  4. ERROR at line 1:
  5. ORA-01476: divisor is equal to zero


  6. SYS@proc> Select 'ok' From aaa where id1/id2=2 and id3/id4=2;

  7. no rows selected

  8. SYS@proc> Select 'ok' From aaa where id3/id4=2 and id1/id2=1;
  9. Select 'ok' From aaa where id3/id4=2 and id1/id2=1
  10.                               *
  11. ERROR at line 1:
  12. ORA-01476: divisor is equal to zero


  13. SYS@proc> Select 'ok' From aaa where id3/id4=2 and id1/id2=2;
  14. Select 'ok' From aaa where id3/id4=2 and id1/id2=2
  15.                               *
  16. ERROR at line 1:
  17. ORA-01476: divisor is equal to zero
②和④只是位置不同,但是一个却正常执行,一个却报错了。
这里查看两条sql的执行计划:
  1. SYS@proc> explain plan for Select 'ok' From aaa where id1/id2=2 and id3/id4=2;

  2. Explained.

  3. SYS@proc> select * from table(dbms_xplan.display());

  4. PLAN_TABLE_OUTPUT
  5. --------------------------------------------------------------------------------
  6. Plan hash value: 864433273

  7. -----------------------------------------------------------------------
  8. | Id | Operation         | Name | Rows | Bytes | Cost (%CPU)| Time     |
  9. ------------------------------------------------------------------------
  10. || SELECT STATEMENT  |      |    1 |    12 |     2   (0)| 00:00:01 |
  11. |* 1 |  TABLE ACCESS FULL| AAA  |    1 |    12 |     2   (0)| 00:00:01 |
  12. -----------------------------------------------------------------------

  13. Predicate Information (identified by operation id):
  14. ---------------------------------------------------

  15. PLAN_TABLE_OUTPUT
  16. --------------------------------------------------------------------------------

  17.    1 - filter("ID1"/"ID2"=2 AND "ID3"/"ID4"=2)

  18. 13 rows selected.

  19. SYS@proc> explain plan for Select 'ok' From aaa where id3/id4=2 and id1/id2=2;

  20. Explained.

  21. SYS@proc> select * from table(dbms_xplan.display());

  22. PLAN_TABLE_OUTPUT
  23. --------------------------------------------------------------------------------
  24. Plan hash value: 864433273

  25. ------------------------------------------------------------------------
  26. | Id | Operation         | Name | Rows | Bytes | Cost (%CPU)| Time     |
  27. ------------------------------------------------------------------------
  28. |  0 | SELECT STATEMENT  |      |    1 |    12 |     2   (0)| 00:00:01 |
  29. |* 1 |  TABLE ACCESS FULL|  AAA |    1 |    12 |     2   (0)| 00:00:01 |
  30. ------------------------------------------------------------------------

  31. Predicate Information (identified by operation id):
  32. ---------------------------------------------------

  33. PLAN_TABLE_OUTPUT
  34. --------------------------------------------------------------------------------

  35.    1 - filter("ID3"/"ID4"=2 AND "ID1"/"ID2"=2)

  36. 13 rows selected.
这里对比谓词信息刚好是两个位置不同,导致执行结果不一样。
正好说明上边的问题的猜想:
     最后猜想Oracle在 filter ( "NAME" = 'db_block_size' AND TO_NUMBER ( "VALUE" ) = 8192 ) 这个步骤,是先对数据做name='db_block_size'的过滤,在做to_number('value')=8192的过滤。
     若是能将谓词信息改变成 filter (TO_NUMBER("VALUE") AND "NAME"='db_block_size'= 8192 ) 并且执行报错,那么猜想就是正确的。

由此问题解决。

其他:
  1. SYS@proc> create table test (id int);

  2. Table created.

  3. SYS@proc> insert into test values(null);

  4. 1 row created.
  5. SYS@proc> commit;

  6. Commit complete.

  7. SYS@proc> select * from test;

  8.     ID
  9. ----------


  10. SYS@proc> set autotrace on
  11. SYS@proc> select value from t,test a where a.id||name='db_block_size' and to_number(a.id||t.value)=8192;

  12. VALUE
  13. --------------------------------------------------------------------------------
  14. 8192


  15. Execution Plan
  16. ----------------------------------------------------------
  17. Plan hash value: 423998170

  18. ---------------------------------------------------------------------------
  19. | Id | Operation          | Name  | Rows | Bytes | Cost (%CPU)| Time     |
  20. ---------------------------------------------------------------------------
  21. |  0 | SELECT STATEMENT   |       |    1 |    39 |    6    (0)| 00:00:01 |
  22. |  1 |  NESTED LOOPS      |       |    1 |    39 |    6    (0)| 00:00:01 |
  23. |  2 |   TABLE ACCESS FULL| TEST  |    1 |    13 |    2    (0)| 00:00:01 |
  24. |* 3 |   TABLE ACCESS FULL| T     |    1 |    26 |    4    (0)| 00:00:01 |
  25. ---------------------------------------------------------------------------

  26. Predicate Information (identified by operation id):
  27. ---------------------------------------------------

  28.    3 - filter(TO_CHAR("A"."ID")||"NAME"='db_block_size' AND
  29.      TO_NUMBER(TO_CHAR("A"."ID")||"T"."VALUE")=8192)

  30. Note
  31. -----
  32.    - dynamic sampling used for this statement (level=2)


  33. Statistics
  34. ----------------------------------------------------------
  35.      32 recursive calls
  36.      0 db block gets
  37.      28 consistent gets
  38.      0 physical reads
  39.      0 redo size
  40.     525 bytes sent via SQL*Net to client
  41.     523 bytes received via SQL*Net from client
  42.      2 SQL*Net roundtrips to/from client
  43.      4 sorts (memory)
  44.      0 sorts (disk)
  45.      1 rows processed

  46. SYS@proc> set autotrace off
  47. SYS@proc> select value from t,test a where to_number(a.id||t.value)=8192 and a.id||name='db_block_size';
  48. select value from t,test a where to_number(a.id||t.value)=8192 and a.id||name='db_block_size'
  49.                                                 *
  50. ERROR at line 1:
  51. ORA-01722: invalid number


  52. SYS@proc> explain plan for select value from t,test a where to_number(a.id||t.value)=8192 and a.id||name='db_block_size';

  53. Explained.

  54. SYS@proc> select * from table(dbms_xplan.display());

  55. PLAN_TABLE_OUTPUT
  56. --------------------------------------------------------------------------------
  57. Plan hash value: 423998170

  58. ---------------------------------------------------------------------------
  59. | Id | Operation          | Name  | Rows | Bytes | Cost (%CPU)| Time     |
  60. ---------------------------------------------------------------------------
  61. |  0 | SELECT STATEMENT   |       |    1 |    39 |    6    (0)| 00:00:01 |
  62. |  1 |  NESTED LOOP     |       |    1 |    39 |    6    (0)| 00:00:01 |
  63. |  2 |   TABLE ACCESS FULL| TES  |    1 |    13 |    2    (0)| 00:00:01 |
  64. |* 3 |   TABLE ACCESS FULL| T     |    1 |    26 |    4    (0)| 00:00:01 |
  65. ---------------------------------------------------------------------------


  66. PLAN_TABLE_OUTPUT
  67. --------------------------------------------------------------------------------
  68. Predicate Information (identified by operation id):
  69. ---------------------------------------------------

  70.    3 - filter(TO_NUMBER(TO_CHAR("A"."ID")||"T"."VALUE")=8192 AND
  71.      TO_CHAR("A"."ID")||"NAME"='db_block_size')

  72. 16 rows selected.

所以where后边条件的执行顺序,实际上和执行计划谓词信息的顺序有关,和where的位置无关。
网上有些在10g做实验得出结论是从右到左,在11g里边,按照相同步骤执行并得不出相同结论。

问题延伸:
filter ( "NAME" = 'db_block_size' AND TO_NUMBER ( "VALUE" ) = 8192 ) ,这里是一次性扫描出全部数据在进行过滤,还是一行一行获取在判断的。
延伸链接: http://blog.itpub.net/30174570/viewspace-2149212/

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/30174570/viewspace-2148607/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/30174570/viewspace-2148607/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值