質問

重複するデータがある場合、Oracleは複数のbetween句をフラット化しますか?私のアプリケーションでは、ユーザーは動的な検索用語を作成できるため、データが重複する可能性があります。 OracleはSQLを最適化しますか、またはSQLを作成する前に計算する必要がありますか?

i.e。

xxtable WHERE id(BETWEEN 10 AND 20)または(BETWEEN 18 AND 30)からIDを選択します

「現状のまま」実行されますか?または変換後:

xxtable WHERE id(BETWEEN 10 AND 30)からIDを選択します

お時間をいただきありがとうございます。

役に立ちましたか?

解決

オプティマイザがどのように処理するかは、クエリに依存します。 autotraceを使用して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

これについて、オプティマイザーは、両方の条件に同じ上限があることを認識していることがわかります。そのため、オプティマイザがどのように書き換えるかについてはクエリに依存します。

他のヒント

インデックス付きの実際のテーブルに対して試行を実行すると何が起こるかを見る価値があります。このサンプルテーブルには、69,241行と、COL_3の統計情報付きの一意でないインデックスがあります。

ケース1 :基本的な2つの重複する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>

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>

アップショット:インデックスは無視され、全表スキャンが実行されます

ケース4: 2つのBETWEEN範囲が1つの句にマージされます

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:インデックスは、上限と下限の両方に使用されます

したがって、要約すると、2つのBETWEEN句が重複し、列にインデックスがある場合は、それらをマージする価値があります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top