这是使用相同子查询的三种不同选择。如何使用子查询结果而不是再次执行子查询。
SELECT *
FROM Address
WHERE address_key IN
(
SELECT address_key
FROM person_address
WHERE peson_key IN (person_list)
); -- person_list := '1,2,3,4'
SELECT *
FROM Phone
WHERE phone_key IN
(
SELECT address_key
FROM person_address
WHERE peson_key IN (person_list)
);
SELECT *
FROM Email
WHERE address_key IN
(
SELECT address_key
FROM person_address
WHERE peson_key IN (person_list)
);
答案 0 :(得分:6)
您可以为此查询创建实体化视图:
CREATE MATERIALIZED VIEW v_address
REFRESH FORCE ON COMMIT
AS
SELECT address_key
FROM person_address
WHERE person_key IN (person_list)
,或者创建一个临时表并填充它:
CREATE GLOBAL TEMPORARY TABLE tt_address (VARCHAR2(50));
INSERT
INTO tt_address
SELECT address_key
FROM person_address
WHERE person_key IN (person_list)
,但是,实际上,如果您索引person_key
,则可以重用子查询。
由于您有3
个单独的查询,因此您需要以这样或那样的方式显示您的值。
这意味着您需要将这些值存储在某处,无论是内存,临时表空间还是永久表空间。
但您需要的值已经存储在person_address
中,您只需要获取它们。
使用子查询3
次将涉及12
索引扫描,以从ROWID
和person_key
表{{1}上的索引中获取12
查找从表中获取ROWID
。那么很可能会在它们之上构建address_key
。
这是一个微秒的问题。
当然,临时表或物化视图会更有效率,但是将子查询时间从HASH TABLE
微秒更改为100
几乎不值得,只要主要查询可以采取分钟。
答案 1 :(得分:6)
使用with子句。我没有重新创建您的确切示例问题,但可以在WITH子句中放入任意数量的重复子查询,然后在查询中引用。
WITH address_keys as (
SELECT address_key
FROM person_address
WHERE peson_key IN (person_list)
)
Select * from table1, table2, address_keys
where table1.address_key = address_keys.address_key
and table2.address_key = address_keys.address_key
答案 2 :(得分:4)
首先,我认为在大多数情况下,此优化不会带来显着改进(在第一次查询之后,PERSON_ADDRESS的数据块将主要缓存在缓冲区缓存中,因此无法从HDD读取)。
然而,作为案例研究或出于任何原因: 您需要缓存重复的查询结果,然后在3个选择中重复使用它们。这可以通过(temp)表或MV或plsql结构varray来实现。
前两个选项在他的回答中涵盖了Quassnoi,所以我不会提及它们。第三个缺点是必须事先声明最大行数(我不知道当你声明一个上限为1M或1G项目的varray时会发生什么,即使你只需要1k)。
--creating db object to hold the data - maximum of 1000 items allowed.
--I assume that key is number(10,0).
create type t_address_keys is varray (1000) of number (10,0);
declare
la_address_keys t_address_keys; --declare cache variable
begin
--cache keys
SELECT address_key
bulk collect into la_address_keys
FROM person_address
WHERE peson_key IN (person_list);
SELECT *
into ...
FROM Address
WHERE address_key IN table(la_address_keys);
SELECT *
into ...
FROM Phone
WHERE address_key IN table(la_address_keys);
SELECT *
into ...
FROM email
WHERE address_key IN table(la_address_keys);
end;
/