我不明白为什么这个查询非常慢(+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) */
提示,但没有效果。
如果有人知道我可以在这种情况下使用的提示,强制执行引擎缓存远程查询的结果,请告知,我会接受你的回答。
答案 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
上建立索引可能是个好主意