我应该在join条件或之前的cte中放置行号筛选器吗?

ltqd579y  于 2021-06-26  发布在  Impala
关注(0)|答案(1)|浏览(380)

我有一个 subscription 表和a payments 我需要加入的表。我试图在两个选项之间做出选择,性能是一个关键的考虑因素。
下面两个选项中哪一个会表现更好?
我使用的是impala,这些表很大(数百万行),我只需要为每个表获取一行 id 以及 date 分组(因此 row_number() 解析函数)。
为了说明我的问题,我缩短了提问时间:
方案1:

WITH cte
   AS (
   SELECT *
      , SUM(amount) OVER (PARTITION BY id, date) 
        AS sameday_total
      , ROW_NUMBER() OVER (PARTITION BY id, date ORDER BY purchase_number DESC)
        AS sameday_rownum
   FROM payments
), 
payment
AS (
    SELECT * 
    FROM cte
    WHERE sameday_rownum = 1
    )
    SELECT s.* 
       , p.sameday_total
    FROM subscription
    INNER JOIN payment ON s.id = p.id

方案2:

WITH payment
   AS (
   SELECT *
          , SUM(payment_amount) OVER (PARTITION BY id, date) 
            AS sameday_total
          , ROW_NUMBER() OVER (PARTITION BY id, date ORDER BY purchase_number DESC)
            AS sameday_rownum
   FROM payments
)
SELECT s.*
       , p.sameday_total
FROM subscription
INNER JOIN payment ON s.id = p.id
                  AND p.sameday_rownum = 1
ndasle7k

ndasle7k1#

“选项0”也存在。一个更传统的“派生表”,它不需要使用任何cte。

SELECT s.*
       , p.sameday_total
FROM subscription
INNER JOIN (
           SELECT *
             , SUM(payment_amount) OVER (PARTITION BY id, date) 
                 AS sameday_total
             , ROW_NUMBER() OVER (PARTITION BY id, date ORDER BY purchase_number DESC)
                AS sameday_rownum
           FROM payments
           ) p ON s.id = p.id
                  AND p.sameday_rownum = 1

所有选项0、1和2都可能产生相同或非常相似的解释计划(尽管我对sql server的该语句比impala更有信心)。
采用cte本身并不能提高查询的效率和性能,因此选项1和选项2之间的语法改变并不重要。我自己更喜欢选项0,因为我更喜欢将CTE用于特定任务(例如递归)。
你应该做的是使用解释计划来研究每个选项产生的结果。

相关问题