【问题标题】:Oracle conditional joinOracle 条件连接
【发布时间】:2012-08-16 17:44:13
【问题描述】:

TL;DR:如果参数说明,我想消除整个连接+子选择。

假设我在这样的存储过程中有一个查询:

open cur_result for
select t1.* from table1 t1
join (select key, value, row_number() over (partition by key order by whatever) rn from table2) t2
on t1.key = t2.key and t2.rn = 1
where [...lots of things...]
and t2.value = 'something'

你看,我不只是将 table1 连接到 table2,我只需要根据某些条件连接 table2 的第一条记录,因此子查询中的 row_number 计算和 rn=1 附加连接条件。不管怎样,关键是这是一个昂贵的子查询,我想根据这个子查询进行过滤。

我的目标是这个子查询应该是有条件的,基于一个额外的参数。如果我想重复所有内容,如下所示:

if should_filter_table2 = 1 then
  [the above query is copied here completely]
else
  open cur_result for
  select t1.* from table1 t1
  -- no table2 join
  where [...lots of things...]
  -- no table2 condition
end if;

问题是可能有很多这样的参数和几乎相同的 SQL 的许多分支,这看起来很难看并且难以维护。我也可以这样做:

open cur_result for
select t1.* from table1 t1
join (select key, value, row_number() over (partition by key order by whatever) rn from table2) t2
on t1.key = t2.key and t2.rn = 1
where [...lots of things...]
and (should_filter_table2 = 0 or t2.value = 'something')

这很容易维护,但是如果参数说子查询无关紧要,仍然是无条件执行。根据我的经验,Oracle 无法对此进行优化,这会对性能造成巨大影响。

所以问题是:你能在 1 个查询中做到这一点并且性能良好吗?像这样的:

open cur_result for
select t1.* from table1 t1
join {case when should_filter_table2 = 1 then (select key, value, row_number() over (partition by key order by whatever) rn from table2) else [empty table] end} t2
on t1.key = t2.key and t2.rn = 1
where [...lots of things...]
and (should_filter_table2 = 0 or t2.value = 'something')

所以如果 should_filter_table2 为 0,则不应该计算子查询并且根本不应该应用过滤器。

应避免使用动态 SQL。我怀疑如何在动态 SQL 中执行此操作,但它会引发相同的可维护性问题。

【问题讨论】:

    标签: oracle select join plsql


    【解决方案1】:

    我不是 100% 确定优化器是否按照我认为的那样做,但我可能会从以下内容开始。不幸的是,我手头没有测试数据来模拟长时间运行的查询。

    select t1.* from table1 t1
      where 
        (should_filter_table2 = 0 or (
            (t1.key, 'something', 1) in (
                 select key, value, row_number() over 
                                   (partition by key order by whatever) rn 
                   from table2) 
            )
        )
      and [...lots of things...]
    

    【讨论】:

    • 这对我来说看起来不错,尽管我认为它需要稍微修改一下,因为条件 value = 'something' 需要在 row_number 之后进行评估
    • @MikeMeyers 感谢您的澄清。我错过了。我已经更新了 select 语句。
    猜你喜欢
    • 1970-01-01
    • 2022-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-26
    • 2014-06-15
    • 1970-01-01
    • 2011-08-15
    相关资源
    最近更新 更多