优化where子句中的SQL子查询

Posted

技术标签:

【中文标题】优化where子句中的SQL子查询【英文标题】:Optimising SQL sub query in where clause 【发布时间】:2015-07-16 20:45:07 【问题描述】:

我有使用下面的 Oracle SQL Developer 的 sql,但我担心更大的实时数据库的性能。

请原谅所有的连接表,这是显示与保存审计历史的 _aud 表和修订表的连接。

select cust.forename, cust.surname
from customer cust
join section_details sd on cust.section = sd.section
where
-- this value is substituted programatically
sd.type = 5 and
(
  (select max(rt.timestamp)
  from
  customer cust_tmp1
  join section_details sd on cust_tmp1.section = sd.section
  join measure msr on sd.measure = msr.id
  join measure_aud msr_a on msr.id = msr_a.id
  join revision_table rt on msr_a.rev = rt.id
  where
  cust_tmp1.id = cust.id and msr.measure = 'Last Contact Date')
> 
  (select max(rt.timestamp)
  from
  customer cust_tmp2
  join section_details sd on cust_tmp2.section = sd.section
  join measure msr on sd.measure = msr.id
  join measure_aud msr_a on msr.id = msr_a.id
  join revision_table rt on msr_a.rev = rt.id
  where
  cust_tmp2.id = cust.id and  msr.measure = 'Last Order Date')
);

简而言之,如果“最后联系日期”比“最后订单日期”更近,我只想检索客户详细信息。我最终检查了一个选择的 max(timestamp) 是否大于另一个选择的 max(timestamp)。

一切正常,我得到了我期望的结果。

除了 msr.measure = 'Last Contact Date' 或 'Last Order Date' 之外,时间戳比较的每一边都是重复的。

我尝试了一些从未真正起作用的替代方案,因为它们导致多级嵌套子查询,并且我无法传递外部客户记录。

任何进一步的想法将不胜感激。

【问题讨论】:

请用您正在使用的数据库标记您的问题。 我已用 oracle11g 标记并更新了我的问题。感谢回复 【参考方案1】:

您确定需要所有这些连接吗?

具有不同 WHERE 条件的相同查询通常转换为 CASE:

select cust.forename, cust.surname
from customer cust
where
  -- this value is substituted programatically
   sd.type = 5 
and exists
 ( select *
   from
   customer cust_tmp1
   join section_details sd on cust_tmp1.section = sd.section
   join measure msr on sd.measure = msr.id
   join measure_aud msr_a on msr.id = msr_a.id
   join revision_table rt on msr_a.rev = rt.id
   where cust_tmp1.id = cust.id

   having max(case when msr.measure = 'Last Contact Date' then rt.timestamp end)
        > max(case when msr.measure = 'Last Order Date'   then rt.timestamp end)
 )

或简化删除子查询:

select cust.forename, cust.surname
from customer cust
join section_details sd on cust_tmp1.section = sd.section
join measure msr on sd.measure = msr.id
join measure_aud msr_a on msr.id = msr_a.id
join revision_table rt on msr_a.rev = rt.id
where
  -- this value is substituted programatically
   sd.type = 5 
group by cust.forename, cust.surname
having max(case when msr.measure = 'Last Contact Date' then rt.timestamp end)
     > max(case when msr.measure = 'Last Order Date'   then rt.timestamp end)

【讨论】:

【参考方案2】:

您可以将其切换为exists

exists (select max(rt.timestamp)
        from customer cust_tmp1 join
             section_details sd
             on cust_tmp1.section = sd.section join
             measure msr
             on sd.measure = msr.id join
             measure_aud msr_a
             on msr.id = msr_a.id join
             revision_table rt
             on msr_a.rev = rt.id
        where cust_tmp1.id = cust.id and
              msr.measure in ( 'Last Contact Date', 'Last Order Date')
        having max(case when msr.measure = 'Last Contact Date' then rt.timestamp end) >
               max(case when msr.mesure = 'Last Order Date' then rt.timestamp end)
       );

我不确定是否会有很大的性能提升。如果您在数据库中设置了正确的索引,那么您的原始版本应该非常快速且可扩展。

【讨论】:

【参考方案3】:

我尝试了此处发布的解决方案,它们似乎都有效,非常感谢您的回复 - 我之前没有调查过 having 子句。

我添加了所有必需的索引并对所有选项运行解释计划,我的原始查询成本最低。所以我想我会继续使用这个选项。

【讨论】:

以上是关于优化where子句中的SQL子查询的主要内容,如果未能解决你的问题,请参考以下文章

子选择查询是不是基于它之外的 WHERE 子句进行了优化? [关闭]

深入理解CQL中的Where子句

WHERE 子句中带有子查询的 MYSQL UPDATE 查询 - 优化

Mysql在where子句中优化子查询

Oracle 查询优化器是不是将*** where 子句应用于子查询或视图?

SQL 中 where 后面可不可以跟上子查询