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

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

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

从xxtable WHERE id(BETWEEN 10 AND 30)

中选择id

感谢您的时间。

有帮助吗?

解决方案

这取决于查询优化器将如何处理它。您可以使用autotrace在SQLPlus中测试它并查看Predicate信息(这是在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

在这一点上,我们看到优化器确实认识到标准具有相同上限的位置。因此,它取决于查询优化器将如何重写它。

其他提示

值得一看的是当我们针对带有索引的真实表运行试验时会发生什么。此示例表包含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>

Upshot:忽略索引,然后进行全表扫描

案例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>

Upshot:索引用于上限,避免全表扫描

案例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>

Upshot:忽略索引,然后进行全表扫描

案例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>

Upshot:索引用于上限和下限

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top