2

WHERE次のように、句を含むクエリを (Oracle SQL で) 実行しようとしています。

    SELECT booking_line_id
FROM booking_line
WHERE    (booking_line_id in
  (SELECT sbli.booking_line_id
   FROM search_booking_line_index sbli,
     policy_record pr,
     policy_record_revision prr
   WHERE sbli.attribute_name = 2209
   AND sbli.policy_record_id = pr.policy_record_id
   AND pr.latest_revision_id = prr.policy_record_revision_id
   AND LOWER(prr.broker_reference) LIKE '%123%'));

実行計画:

|   0 | SELECT STATEMENT       |                        | 19027 |   334K|   455   (3)| 00:00:03 |
|   1 |  NESTED LOOPS          |                        | 19027 |   334K|   455   (3)| 00:00:03 |
|   2 |   VIEW                 | VW_NSO_1               | 19027 |   241K|   449   (2)| 00:00:03 |
|   3 |    HASH UNIQUE         |                        | 19027 |   798K|            |          |
|*  4 |     HASH JOIN          |                        | 19027 |   798K|   449   (2)| 00:00:03 |
|*  5 |      HASH JOIN         |                        |   464 | 13456 |    31   (4)| 00:00:01 |
|*  6 |       TABLE ACCESS FULL| POLICY_RECORD_REVISION |   464 |  9280 |    21   (0)| 00:00:01 |
|*  7 |       TABLE ACCESS FULL| POLICY_RECORD          |  4067 | 36603 |     9   (0)| 00:00:01 |
|*  8 |      INDEX RANGE SCAN  | SBLI_ATTRIBUTE_CDX     |   166K|  2282K|   416   (1)| 00:00:03 |
|*  9 |   INDEX UNIQUE SCAN    | BOOKING_LINE_PK        |     1 |     5 |     1   (0)| 00:00:01 |

このクエリは非常に高速に実行され、すぐに行が返されます。しかし、次のように条件を追加するORと、クエリがハングします (または非常に長い時間がかかります)。

    SELECT booking_line_id
FROM booking_line
WHERE 1=0 or   (booking_line_id in
  (SELECT sbli.booking_line_id
   FROM search_booking_line_index sbli,
     policy_record pr,
     policy_record_revision prr
   WHERE sbli.attribute_name = 2209
   AND sbli.policy_record_id = pr.policy_record_id
   AND pr.latest_revision_id = prr.policy_record_revision_id
   AND LOWER(prr.broker_reference) LIKE '%123%'));

実行計画:

|   0 | SELECT STATEMENT               |                           |   166K|   811K|   484   (2)| 00:00:03 |
|*  1 |  FILTER                        |                           |       |       |            |          |
|   2 |   INDEX FAST FULL SCAN         | BOOKING_LINE_PK           |   166K|   811K|    66   (5)| 00:00:01 |
|   3 |   NESTED LOOPS                 |                           |     1 |    43 |   419   (1)| 00:00:03 |
|   4 |    NESTED LOOPS                |                           |     1 |    23 |   418   (1)| 00:00:03 |
|*  5 |     INDEX RANGE SCAN           | SBLI_ATTRIBUTE_CDX        |     1 |    14 |   417   (1)| 00:00:03 |
|*  6 |     TABLE ACCESS BY INDEX ROWID| POLICY_RECORD             |     1 |     9 |     1   (0)| 00:00:01 |
|*  7 |      INDEX UNIQUE SCAN         | POLICY_RECORD_PK          |     1 |       |     1   (0)| 00:00:01 |
|*  8 |    TABLE ACCESS BY INDEX ROWID | POLICY_RECORD_REVISION    |     1 |    20 |     1   (0)| 00:00:01 |
|*  9 |     INDEX UNIQUE SCAN          | POLICY_RECORD_REVISION_PK |     1 |       |     1   (0)| 00:00:01 |

これには最初のクエリと同じ時間がかかるはずです。しかし、驚くべきことに、そうではありませんでした。

誰でも同じ理由で私を助けてもらえますか?

4

2 に答える 2

2

少なくとも 11gR2 では、計画と実行はまったく同じです。これが私のセットアップです:

CREATE TABLE table1 AS SELECT * FROM dba_objects WHERE object_id IS NOT NULL;
CREATE TABLE table2 AS SELECT * FROM dba_objects WHERE object_id IS NOT NULL 
                                                   AND object_type = 'VIEW';

ALTER TABLE table1 ADD CONSTRAINT table1_pk PRIMARY KEY (object_id);
ALTER TABLE table2 ADD CONSTRAINT table2_pk PRIMARY KEY (object_id);

最初のクエリの実行計画:

SQL> EXPLAIN PLAN FOR SELECT * FROM TABLE1
  2                    WHERE OBJECT_ID IN (SELECT OBJECT_ID FROM TABLE2);

SQL> SELECT * FROM TABLE(dbms_xplan.display);

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 2776518249
--------------------------------------------------------------------------------
| Id  | Operation                    | Name      | Rows  | Bytes | Cost (%CPU)|
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |           | 31523 |  6772K|   584   (1)|
|   1 |  MERGE JOIN                  |           | 31523 |  6772K|   584   (1)|
|   2 |   TABLE ACCESS BY INDEX ROWID| TABLE1    |   396K|    78M|   575   (1)|
|   3 |    INDEX FULL SCAN           | TABLE1_PK |   396K|       |    77   (0)|
|*  4 |   SORT JOIN                  |           | 31523 |   400K|    10  (30)|
|   5 |    INDEX FULL SCAN           | TABLE2_PK | 31523 |   400K|     7   (0)|
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   4 - access("OBJECT_ID"="OBJECT_ID")
       filter("OBJECT_ID"="OBJECT_ID")

SQL>

2 番目のクエリの場合:

SQL> EXPLAIN PLAN FOR SELECT * FROM TABLE1
  2             WHERE 1 = 0 OR OBJECT_ID IN (SELECT OBJECT_ID FROM TABLE2); 

SQL> SELECT * FROM TABLE(dbms_xplan.display);

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 2776518249
--------------------------------------------------------------------------------
| Id  | Operation                    | Name      | Rows  | Bytes | Cost (%CPU)|
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |           | 31523 |  6772K|   584   (1)|
|   1 |  MERGE JOIN                  |           | 31523 |  6772K|   584   (1)|
|   2 |   TABLE ACCESS BY INDEX ROWID| TABLE1    |   396K|    78M|   575   (1)|
|   3 |    INDEX FULL SCAN           | TABLE1_PK |   396K|       |    77   (0)|
|*  4 |   SORT JOIN                  |           | 31523 |   400K|    10  (30)|
|   5 |    INDEX FULL SCAN           | TABLE2_PK | 31523 |   400K|     7   (0)|
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   4 - access("OBJECT_ID"="OBJECT_ID")
       filter("OBJECT_ID"="OBJECT_ID")
于 2012-05-10T09:05:43.690 に答える
0

実行計画を変更するためにサーバーを作成したためのようです。最初のクエリは内部結合で実行されるため、非常に高速です。しかし、2 番目のプロセスでは、最初の条件をチェックしてから、必要に応じて選択を行う必要があります。次のようにクエリを変更できます。

select ... 
 from t
 left join t2
 where 1=0 or t2.id is not null
于 2012-05-10T08:52:20.123 に答える