【问题标题】:Oracle Multiple Overlapping Between StatementsOracle 语句之间的多重重叠
【发布时间】:2009-09-09 19:33:00
【问题描述】:

如果子句之间有重叠的数据,Oracle 会展平多个子句吗?在我的应用程序中,用户可以创建动态搜索词,因此可能存在重叠数据。 Oracle 会为我优化 SQL,还是我必须在创建 SQL 之前计算它?

从 xxtable 中选择 id WHERE id (BETWEEN 10 AND 20) or (BETWEEN 18 AND 30)

它会“按原样”运行还是转换为:

从 xxtable 中选择 id WHERE id (BETWEEN 10 AND 30)

感谢您的宝贵时间。

【问题讨论】:

    标签: sql oracle plsql


    【解决方案1】:

    当我们对带有索引的真实表进行试验时,值得看看会发生什么。此示例表有 69,241 行,在 COL_3 上有一个非唯一索引,带有统计信息。

    案例 1:基本的两个重叠的 BETWEEN 子句

    SQL> set autotrace traceonly exp
    SQL>
    SQL> select * from big_table
      2  where col_3 between 0.8 and 1
      3  or col_3 between 0.9 and 1.1
      4  /
    
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 3993303771
    
    -------------------------------------------------------------------------------
    | Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
    -------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT  |           | 14737 |   805K|   176   (1)| 00:00:03 |
    |*  1 |  TABLE ACCESS FULL| BIG_TABLE | 14737 |   805K|   176   (1)| 00:00:03 |
    -------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       1 - filter("COL_3"<=1.1 AND "COL_3">=0.9 OR "COL_3"<=1 AND
                  "COL_3">=0.8)
    
    SQL>
    

    结果:索引被忽略,然后进行全表扫描

    案例 2: BETWEEN 子句共享一个上限

    SQL> select * from big_table
      2  where col_3 between 0.8 and 1.1
      3  or col_3 between 0.9 and 1.1
      4  /
    
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 1461639892
    
    -----------------------------------------------------------------------------------------
    | Id  | Operation                   | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
    -----------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT            |           |  7924 |   433K|   114   (0)| 00:00:02 |
    |   1 |  TABLE ACCESS BY INDEX ROWID| BIG_TABLE |  7924 |   433K|   114   (0)| 00:00:02 |
    |*  2 |   INDEX RANGE SCAN          | BIG3_IDX  |  7924 |       |    17   (0)| 00:00:01 |
    -----------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       2 - access("COL_3"<=1.1)
           filter("COL_3">=0.8 OR "COL_3">=0.9)
    
    SQL>
    

    结果:索引用于上限,避免了全表扫描

    案例 3: BETWEEN 子句共享一个下限

    SQL> select * from big_table
      2  where col_3 between 0.8 and 1.1
      3  or col_3 between 0.8 and 1.2
      4  /
    
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 3993303771
    
    -------------------------------------------------------------------------------
    | Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
    -------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT  |           | 15146 |   828K|   176   (1)| 00:00:03 |
    |*  1 |  TABLE ACCESS FULL| BIG_TABLE | 15146 |   828K|   176   (1)| 00:00:03 |
    -------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       1 - filter(("COL_3"<=1.2 OR "COL_3"<=1.1) AND "COL_3">=0.8)
    
    SQL>
    

    结果:索引被忽略,然后进行全表扫描

    案例 4:两个 BETWEEN 范围合并为一个子句

    SQL> select * from big_table
      2  where col_3 between 0.8 and 1.1
      3  /
    
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 1461639892
    
    -----------------------------------------------------------------------------------------
    | Id  | Operation                   | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
    -----------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT            |           |  7924 |   433K|   114   (0)| 00:00:02 |
    |   1 |  TABLE ACCESS BY INDEX ROWID| BIG_TABLE |  7924 |   433K|   114   (0)| 00:00:02 |
    |*  2 |   INDEX RANGE SCAN          | BIG3_IDX  |  7924 |       |    17   (0)| 00:00:01 |
    -----------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       2 - access("COL_3">=0.8 AND "COL_3"<=1.1)
    
    SQL>
    

    结果:索引同时用于上限和下限

    因此,总而言之,如果两个 BETWEEN 子句重叠并且列上有索引,那么合并它们可能是值得的。

    【讨论】:

      【解决方案2】:

      这取决于优化器将如何处理它的查询。您可以使用自动跟踪在 SQLPlus 中测试它并查看谓词信息(这是在 Oracle 版本 10.2.0.3 上完成的):

      SQL>set autot traceonly
      SQL>
        1  select l
        2    from (SELECT l
        3            FROM (SELECT LEVEL l
        4                    FROM dual CONNECT BY LEVEL < 20
        5                 )
        6         )
        7   where l between 5 and 10
        8*     or l between 7 and 15;
      
      11 rows selected.
      
      Elapsed: 00:00:00.21
      
      Execution Plan
      ----------------------------------------------------------
      Plan hash value: 2403765415
      
      --------------------------------------------------------------------------------------
      | Id  | Operation                     | Name | Rows  | Bytes | Cost (%CPU)| Time     |
      --------------------------------------------------------------------------------------
      |   0 | SELECT STATEMENT              |      |     1 |    13 |     2   (0)| 00:00:01 |
      |*  1 |  VIEW                         |      |     1 |    13 |     2   (0)| 00:00:01 |
      |*  2 |   CONNECT BY WITHOUT FILTERING|      |       |       |            |          |
      |   3 |    FAST DUAL                  |      |     1 |       |     2   (0)| 00:00:01 |
      --------------------------------------------------------------------------------------
      
      Predicate Information (identified by operation id):
      ---------------------------------------------------
      
         1 - filter("L">=5 AND "L"<=10 OR "L">=7 AND "L"<=15)
         2 - filter(LEVEL<20)
      
      
      Statistics
      ----------------------------------------------------------
                1  recursive calls
                0  db block gets
                0  consistent gets
                0  physical reads
                0  redo size
              494  bytes sent via SQL*Net to client
              403  bytes received via SQL*Net from client
                3  SQL*Net roundtrips to/from client
                1  sorts (memory)
                0  sorts (disk)
               11  rows processed
      

      在这种情况下,优化器不会对 where 条件进行重写,但如果我们稍微改变一下:

      SQL>
        1  select l
        2    from (SELECT l
        3            FROM (SELECT LEVEL l
        4                    FROM dual CONNECT BY LEVEL < 20
        5                 )
        6         )
        7   where l between 5 and 10
        8*     or l between 7 and 10;
      
      6 rows selected.
      
      Elapsed: 00:00:00.20
      
      Execution Plan
      ----------------------------------------------------------
      Plan hash value: 2403765415
      
      --------------------------------------------------------------------------------------
      | Id  | Operation                     | Name | Rows  | Bytes | Cost (%CPU)| Time     |
      --------------------------------------------------------------------------------------
      |   0 | SELECT STATEMENT              |      |     1 |    13 |     2   (0)| 00:00:01 |
      |*  1 |  VIEW                         |      |     1 |    13 |     2   (0)| 00:00:01 |
      |*  2 |   CONNECT BY WITHOUT FILTERING|      |       |       |            |          |
      |   3 |    FAST DUAL                  |      |     1 |       |     2   (0)| 00:00:01 |
      --------------------------------------------------------------------------------------
      
      Predicate Information (identified by operation id):
      ---------------------------------------------------
      
         1 - filter("L"<=10 AND ("L">=5 OR "L">=7))
         2 - filter(LEVEL<20)
      
      
      Statistics
      ----------------------------------------------------------
                0  recursive calls
                0  db block gets
                0  consistent gets
                0  physical reads
                0  redo size
              388  bytes sent via SQL*Net to client
              392  bytes received via SQL*Net from client
                2  SQL*Net roundtrips to/from client
                1  sorts (memory)
                0  sorts (disk)
                6  rows processed
      

      在这一点上,我们看到优化器确实认识到两个 where 条件具有相同的上限。所以它取决于查询优化器将如何重写它。

      【讨论】:

      • 多么棒的答案!谢谢!我想这样做的安全方法是让我确保它最终完成。
      猜你喜欢
      • 1970-01-01
      • 2012-10-21
      • 1970-01-01
      • 1970-01-01
      • 2017-09-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多