select 包含 Union 的优化
Optimalization of select containing Union
我很容易 select:
define account_id = 7
select * from A where ACCOUNT_ID = &account_id
UNION
select * from B where ACCOUNT_ID = &account_id;
我想将 account_id 作为另一个 select 的输入,我是这样做的:
select * from A where ACCOUNT_ID in(select accound_id from ACCOUNTS where EMAIL like 'aa@aa.com') -- id 7 returned
UNION
select * from B where ACCOUNT_ID in(select accound_id from ACCOUNTS where EMAIL like 'aa@aa.com')
如何将其优化为仅调用 select accound_id from ACCOUNTS where EMAIL like 'aa@aa.com'
一次?
这就是 WITH
派上用场的地方
WITH ids AS (select account_id from ACCOUNTS where EMAIL like 'aa@aa.com')
select * from A where ACCOUNT_ID in ids
UNION ALL
select * from B where ACCOUNT_ID in ids;
我也改成了UNION ALL
,因为这样快多了。
我的第一个问题是 union
是否可以用 union all
代替。所以,我的第一次尝试是使用 exists
和 union all
:
select a.*
from a
where exists (select 1
from accounts aa
where aa.account_id = a.account_id and
aa.email = 'aa@aa.com'
)
union all
select b.*
from b
where exists (select 1
from accounts aa
where aa.account_id = b.account_id and
aa.email = 'aa@aa.com'
);
对于此结构,您需要 accounts(account_id, email)
上的索引。 exists
只是在索引中查找值。这确实需要扫描 a
和 b
.
如果查询返回少量行并且您想删除重复项,则 union
并替换 union all
。如果它返回大量行——并且每个 table 中没有重复项,并且有一种简单的方法来识别重复项——那么你可以改为:
with cte_a as (
select a.*
from a
where exists (select 1
from accounts aa
where aa.account_id = a.account_id and
aa.email = 'aa@aa.com'
)
)
select cte_a.*
from ctea_a
union all
select b.*
from b
where exists (select 1
from accounts aa
where aa.account_id = b.account_id and
aa.email = 'aa@aa.com'
) and
not exists (select 1
from cte_a
where cte_a.? = b.? -- whatever is needed to identify duplicates
);
我很容易 select:
define account_id = 7
select * from A where ACCOUNT_ID = &account_id
UNION
select * from B where ACCOUNT_ID = &account_id;
我想将 account_id 作为另一个 select 的输入,我是这样做的:
select * from A where ACCOUNT_ID in(select accound_id from ACCOUNTS where EMAIL like 'aa@aa.com') -- id 7 returned
UNION
select * from B where ACCOUNT_ID in(select accound_id from ACCOUNTS where EMAIL like 'aa@aa.com')
如何将其优化为仅调用 select accound_id from ACCOUNTS where EMAIL like 'aa@aa.com'
一次?
这就是 WITH
派上用场的地方
WITH ids AS (select account_id from ACCOUNTS where EMAIL like 'aa@aa.com')
select * from A where ACCOUNT_ID in ids
UNION ALL
select * from B where ACCOUNT_ID in ids;
我也改成了UNION ALL
,因为这样快多了。
我的第一个问题是 union
是否可以用 union all
代替。所以,我的第一次尝试是使用 exists
和 union all
:
select a.*
from a
where exists (select 1
from accounts aa
where aa.account_id = a.account_id and
aa.email = 'aa@aa.com'
)
union all
select b.*
from b
where exists (select 1
from accounts aa
where aa.account_id = b.account_id and
aa.email = 'aa@aa.com'
);
对于此结构,您需要 accounts(account_id, email)
上的索引。 exists
只是在索引中查找值。这确实需要扫描 a
和 b
.
如果查询返回少量行并且您想删除重复项,则 union
并替换 union all
。如果它返回大量行——并且每个 table 中没有重复项,并且有一种简单的方法来识别重复项——那么你可以改为:
with cte_a as (
select a.*
from a
where exists (select 1
from accounts aa
where aa.account_id = a.account_id and
aa.email = 'aa@aa.com'
)
)
select cte_a.*
from ctea_a
union all
select b.*
from b
where exists (select 1
from accounts aa
where aa.account_id = b.account_id and
aa.email = 'aa@aa.com'
) and
not exists (select 1
from cte_a
where cte_a.? = b.? -- whatever is needed to identify duplicates
);