IN(DB LINK)和局部约束的WHERE子句:慢查询

时间:2014-06-17 11:21:48

标签: sql performance oracle11g

我不明白为什么这个查询非常慢(+5分钟):

SELECT a.*
FROM local a
WHERE a.CREATIE_DT > to_date('17/06/2014 10:30:56','dd/mm/yyyy hh24:mi:ss')
OR (a.ID) IN ( SELECT r.ID FROM remote@testsite r);


----------------------------------------------------
| Id  | Operation          | Name          | Cost  |
----------------------------------------------------
|   0 | SELECT STATEMENT   |               |  1586 |
|   1 |  FILTER            |               |       |
|   2 |   TABLE ACCESS FULL| LOCAL         |  1586 |
|   3 |   REMOTE           | REMOTE        |     2 |
----------------------------------------------------

CREATIE_DT上没有索引。

在以下所有情况下,查询执行速度非常快(~10ms):

SELECT a.*
FROM local a
WHERE a.CREATIE_DT > to_date('17/06/2014 10:30:56','dd/mm/yyyy hh24:mi:ss')

----------------------------------------------------
| Id  | Operation         | Name           | Cost  |
----------------------------------------------------
|   0 | SELECT STATEMENT  |                |  1576 |
|   1 |  TABLE ACCESS FULL| LOCAL          |  1576 |
----------------------------------------------------

SELECT a.*
FROM local a
WHERE (a.ID) IN ( SELECT r.ID FROM remote@testsite r);

--------------------------------------------------------
| Id  | Operation         | Name               | Cost  |
--------------------------------------------------------
|   0 | SELECT STATEMENT             |         |     5 |
|   1 |  NESTED LOOPS                |         |     5 |
|   2 |   SORT UNIQUE                |         |     2 |
|   3 |    REMOTE                    | REMOTE  |     2 |
|   4 |   TABLE ACCESS BY INDEX ROWID| LOCAL   |     2 |
|   5 |    INDEX UNIQUE SCAN         | PRKE_PK |     1 |
----------------------------------------------- --------

SELECT a.*
FROM local a
WHERE  a.CREATIE_DT > to_date('17/06/2014 10:30:56','dd/mm/yyyy hh24:mi:ss')
OR (a.ID) = ( SELECT r.ID FROM remote@testsite r);

请注意最后一种情况中的 = (!)。 任何想法的人?

我尝试了/*+ DRIVING_SITE(a) */提示,但没有效果。

如果有人知道我可以在这种情况下使用的提示,强制执行引擎缓存远程查询的结果,请告知,我会接受你的回答。

2 个答案:

答案 0 :(得分:3)

你似乎已经自己回答了。

in版本会导致Oracle优化器为每一行多次重新运行子查询。具有=的版本已经过优化,因此Oracle只会调用远程服务器并缓存结果。

您可以通过将查询作为join

来解决此问题
SELECT a.*
FROM local a JOIN
      (SELECT DISTINCT r.ID FROM remote@testsite r
      ) r
     ON a.ID = r.ID
WHERE a.CREATIE_DT > to_date('17/06/2014 10:30:56','dd/mm/yyyy hh24:mi:ss');

请注意在DISTINCT中使用SELECT来防止行重复。如果您知道r.id是唯一的,则可能没有必要这样做。

编辑:

要获得原始查询的等价物(其中有or而不是and):

SELECT a.*
FROM local a LEFT JOIN
      (SELECT DISTINCT r.ID FROM remote@testsite r
      ) r
     ON a.ID = r.ID
WHERE a.CREATIE_DT > to_date('17/06/2014 10:30:56','dd/mm/yyyy hh24:mi:ss') or
      r.ID is not null;

答案 1 :(得分:1)

只是想一想,这是怎么表现的?

SELECT a.*
FROM local a
WHERE a.CREATIE_DT > to_date('17/06/2014 10:30:56','dd/mm/yyyy hh24:mi:ss')
UNION
SELECT a.*
FROM local a
WHERE (a.ID) IN ( SELECT r.ID FROM remote@testsite r);

在CREATIE_DT

上建立索引可能是个好主意