为什么这个相关子查询比窗口函数更快?

问题描述 投票:0回答:1

两个查询:

select tbraccd_pidm, 
       max(tbraccd_balance) 
       keep (dense_rank first order by tbraccd_tran_number) 
       over (partition by tbraccd_pidm)
from tbraccd;
select tbraccd_pidm, tbraccd_balance
from tbraccd a
where tbraccd_tran_number = (select max(tbraccd_tran_number)
                             from tbraccd b 
                             where b.tbraccd_pidm = a.tbraccd_pidm);

他们的自动跟踪:

PK_TBRACCD
TBRACCD_PIDM
TBRACCD_TRAN_NUMBER
的索引。

根据 V$Stats,第一次查询使用 2.43x CPU 来完成第一次调用而不是第二次调用,并且在 DB 时间上的差异大致相同。

他们使用相同的索引,并且每个人都在执行 FULL SCAN。为什么第二个功能表现得更好?

oracle12c sql-execution-plan
1个回答
0
投票

第一个查询:

select tbraccd_pidm, 
       max(tbraccd_balance) 
       keep (dense_rank first order by tbraccd_tran_number) 
       over (partition by tbraccd_pidm)
from tbraccd;

将返回表中的所有行;您在

SELECT
子句中找到最大值,但它未在
WHERE
子句中用于过滤结果集,因此您返回每一行。

这也是不同的,因为您使用的是

DENSE_RANK FIRST
,它找到最小值,而不是
DENSE_RANK LAST
(或
DENSE_RANK FIRST ORDER BY ... DESC
)来找到最大值。

比较:

select tbraccd_pidm, tbraccd_balance
from tbraccd a
where tbraccd_tran_number = (select max(tbraccd_tran_number)
                             from tbraccd b 
                             where b.tbraccd_pidm = a.tbraccd_pidm);

有一个

WHERE
子句,查询只需要返回结果的一个子集。


如果您希望查询等效,那么第一个查询应该是:

SELECT tbraccd_pidm, 
       tbraccd_balance
FROM   (
  SELECT tbraccd_pidm, 
         tbraccd_balance,
         RANK() OVER (partition by tbraccd_pidm ORDER BY tbraccd_tran_number) AS rnk
  FROM   tbraccd
)
WHERE  rnk = 1;

SELECT tbraccd_pidm,
       tbraccd_balance
FROM   (
  select tbraccd_pidm,
         tbraccd_balance,
         tbraccd_tran_number,
         MAX(tbraccd_tran_number) OVER (partition by tbraccd_pidm) AS max_number
  from tbraccd
)
WHERE  tbraccd_tran_number = max_number;
© www.soinside.com 2019 - 2024. All rights reserved.