sql - OR 条件使查询执行速度变慢

标签 sql oracle

我正在尝试执行一个带有 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 |

预计这应该与第一个查询花费相同的时间。但令人惊讶的是,事实并非如此。

谁能帮我解释一下原因吗?

最佳答案

至少在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>

对于第二个查询:

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")

关于sql - OR 条件使查询执行速度变慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10530088/

相关文章:

sql - 如何在 Oracle 中旋转表?

mysql - SQL - 选择最常出现的值

sql - 在 sql server 存储过程中创建和循环列表

mysql - 如何在 Oracle 中设置固定时间分钟和秒与当前小时

sql - 需要修剪oracle中的空格

java - TomEE ORA-01017 服务器尝试通过操作系统用户进行身份验证

sql - 如何比较表中最后一个和倒数第二个条目的值?

sql - MDX查询的两种情况

sql - 连接可能包含空值的人名的最短 TSQL 是什么

mysql - 按正确顺序从一张表中选择 parent 和 child