为啥在 Oracle 中使用 CASE 进行子选择比 JOIN WITH OR 更快

Posted

技术标签:

【中文标题】为啥在 Oracle 中使用 CASE 进行子选择比 JOIN WITH OR 更快【英文标题】:Why is subselect with CASE is faster than JOIN WITH OR in Oracle为什么在 Oracle 中使用 CASE 进行子选择比 JOIN WITH OR 更快 【发布时间】:2015-07-01 10:03:40 【问题描述】:

我正在优化我们拥有的一个可怕的视图,令人惊讶的是,带有CASE 语句的子选择之一比带有ORLEFT JOIN 运行得更快。原始视图要大得多,但我感兴趣的部分可以归结为以下查询

SELECT CASE 
     WHEN tdcurr.productid = 1 THEN (SELECT addressid 
                                     FROM   address a 
                                     WHERE  a.customerid = tm.customerid 
                                            AND a.addressid = 
                                                tdcurr.addressid 
                                            AND a.addresstypeid = 3) 
     WHEN tdcurr.productid = 2 THEN (SELECT addressid 
                                     FROM   address a 
                                     WHERE  a.customerid = tm.customerid 
                                            AND a.addressid = 
                                                tdcurr.addressid 
                                            AND a.addresstypeid = 4) 
   END AS t_buyselladdressid 
FROM   vleaf_transactiondetail_all tdcurr 
   inner join transactionmain tm 
           ON tm.transactionid = tdcurr.transactionid 

执行计划

而加入的人总是较慢

SELECT bsaddr.addressid AS t_buyselladdressid 
FROM   vleaf_transactiondetail_all tdcurr 
   inner join transactionmain tm 
           ON tm.transactionid = tdcurr.transactionid 
   left outer join address bsaddr 
                ON tm.customerid = bsaddr.customerid 
                   AND bsaddr.addressid = tdcurr.addressid 
                   AND ( ( tdcurr.productid = 1 
                           AND bsaddr.addresstypeid = 3 ) 
                          OR ( tdcurr.productid = 2 
                               AND bsaddr.addresstypeid = 4 ) ) 

执行计划

为什么会这样?

【问题讨论】:

我不会真正相信工具的时间安排(尤其是小数点)。有时我几乎只等待几毫秒的响应。如果您想了解差异,请调查执行计划。 @MarmiteBomber 添加了执行计划。 我认为我要做的是修改连接案例以使用以下形式的子句:a.addresstypeid = (case tdcurr.productid when 1 then 3 when 2 then 4 end) 【参考方案1】:

带有子选择的 SQL 可能受益于标量子查询缓存。从解释计划来看,它肯定会从不执行嵌套循环外连接中受益!

有关标量子查询缓存的更多信息,请参阅https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:2683853500346598211。

【讨论】:

我认为这(子查询缓存)可能是正确的解释,以防有很多交易记录而只有少数客户。 NL 将为每个交易记录循环,但每个客户只调用一次子查询。 @Matas Vaitkevicius 请提供 transactionId 的数量和 customerId 的 distict 数量。

以上是关于为啥在 Oracle 中使用 CASE 进行子选择比 JOIN WITH OR 更快的主要内容,如果未能解决你的问题,请参考以下文章

为啥我不能在计算列的 case 语句中使用子查询

Oracle SQL:对 CASE WHEN 重复使用子查询,而无需重复子查询

在 oracle 中的 case 或 decode 语句中使用 sum

oracle不可以用order by么

如何优化涉及内部连接的条件子选择?

如何使用 case 语句对子选择的结果进行排序