【问题标题】:UNION clause performance issue with sqlsql 的 UNION 子句性能问题
【发布时间】:2016-09-16 12:33:25
【问题描述】:

我有以下联合子句导致整个存储过程运行非常缓慢。我正在使用 union 从同一个表中收集信息,但是第二个和第三个 union 子句也连接到其他表以进行过滤。我知道这可能不是最好的编码方法,希望有人可以指导我更好的语法。

select ss.int_tran_id 
from status ss 
where ss.stage in ('ACHPayment_Confirmed', 'HIFV4', 'HIFV5_FTRINF', 'Payment_HIFV5_FTRINF')
UNION
select ss.int_tran_id 
from status ss, references rf
where ss.int_tran_id = rf.int_tran_id
and ss.stage = 'PREVDAY'
and rf.mid_ref IS NOT NULL
UNION
select ss.int_tran_id 
from status ss, app_data ad, ach aa
where ss.int_tran_id = ad.int_tran_id
and ad.app_data_id = aa.ach_id
and ss.stage = 'PREVDAY'
and aa.par_number IS NOT NULL

【问题讨论】:

  • 请发布您的表结构,包括索引和查询的解释计划,以帮助人们了解正在发生的事情以及如何改进您的查询
  • 记录是否不同?如果是,请使用 UNION ALL。除非发布执行计划,否则没有更多提示 :)
  • 有点长,我可以把它作为文件附件发在这里吗?不,这些记录并不明显
  • 跳过 UNION 的。将 EXISTS 添加到第一个选择中。

标签: sql oracle union


【解决方案1】:

我认为您可以将其重写为状态表上的单个查询,使用 OR 来测试每个场景,如下所示:

SELECT ss.int_tran_id
FROM   status SS
WHERE  ss.stage in ('ACHPayment_Confirmed', 'HIFV4', 'HIFV5_FTRINF', 'Payment_HIFV5_FTRINF')
OR     (ss.stage = 'PREVDAY'
        AND (EXISTS (SELECT NULL
                     FROM   references rf
                     WHERE  ss.int_tran_id = rf.int_tran_id
                     AND    rf.mid_ref IS NOT NULL)
             OR EXISTS (SELECT NULL
                        FROM   app_data ad
                               INNER JOIN ach aa
                                 ON (ad.app_data_id = aa.ach_id)
                        WHERE  ss.int_tran_id = ad.int_tran_id
                        AND    aa.par_number IS NOT NULL)));

【讨论】:

  • 感谢 Boneist,它使执行时间减少了 60%。非常感谢您的帮助!
  • 感谢您转换为使用显式联接。任何人都不应该使用隐式连接。
【解决方案2】:

考虑在一个 SELECT 中编写整个查询(使用括号、AND、OR),这样可以消除 UNION 的所有低效重复检查。

您可以按照 Pawel-Dyl 的建议尝试 UNION ALL,但如果您能做到这一点,您可能可以在一个 SELECT 中全部编写,这为优化器提供了更多选择。

【讨论】:

    【解决方案3】:

    我的变种:

    select ss.int_tran_id 
    from status ss
    left join references rf on (ss.stage = 'PREVDAY'
                                and ss.int_tran_id = rf.int_tran_id
                                and rf.mid_ref IS NOT NULL)
    left join app_data ad on (ss.stage = 'PREVDAY'
                              and ss.int_tran_id = ad.int_tran_id)
    left join ach aa on (ss.stage = 'PREVDAY'
                         and ad.app_data_id = aa.ach_id
                         and aa.par_number IS NOT NULL)
    where ss.stage in ('ACHPayment_Confirmed', 'HIFV4', 'HIFV5_FTRINF', 'Payment_HIFV5_FTRINF')
       or rf.int_tran_id is not null
       or aa.ach_id is not null
    

    【讨论】:

    • 如果每个 int_tran_id / ach_id 的引用、app_data 或 ach 表中有多行,这很可能会引入额外的行。您需要一个额外的 distinct 来删除重复项,除非您绝对确定连接都是 1-1 条件...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-03
    相关资源
    最近更新 更多