【问题标题】:Optimalization of select containing Union包含Union的select的优化
【发布时间】:2019-12-03 10:08:03
【问题描述】:

我有并且很容易选择:

define account_id = 7
select * from A where ACCOUNT_ID = &account_id
UNION
select * from B where ACCOUNT_ID = &account_id;

我想将 account_id 作为另一个选择的输入,我这样做了:

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'

【问题讨论】:

  • 第1步:你能用UNION ALL代替UNION吗?
  • select accound_id from ACCOUNTS where EMAIL like 'aa@aa.com 将此查询的结果分配给一个变量并在联合中使用该变量
  • 使用 where exists 而不是 In 语句重写查询
  • 我先UNION [ALL],然后将结果与当前子查询连接起来。
  • 但主要的问题是,为什么你有两张如此相似的表A和B?你不能用一张公用表来代替吗?

标签: sql oracle union query-performance


【解决方案1】:

我的第一个问题是union 是否可以替换为union all。所以,我的第一次尝试是使用existsunion 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 只是在索引中查找值。这确实需要扫描ab

如果查询返回少量行并且您想要删除重复项,则使用union 并替换union all。如果它返回一大组行——并且每个表中没有重复项,并且有一种简单的方法可以识别重复项——那么你可以这样做:

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

【讨论】:

    【解决方案2】:

    这就是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,因为它更快。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-18
      相关资源
      最近更新 更多