【问题标题】:Partial count aggregation部分计数聚合
【发布时间】:2020-01-16 11:05:12
【问题描述】:

注意:虽然我目前的重点是 tsql,但这很可能是一个更一般的 sql 问题。

考虑以下有效但也是伪代码示例查询:

select 
    desiredKeyCols,
    case count(distinct productID) 
        when 0 then '0'
        when 1 then '1'
        else '2+'
    end as [Product Count Classification]
from orders
group by desiredKeyCols

对于每个 desiredKeyCols,字段 [产品计数分类] 将返回 0,如果没有关联的 productIDs,1 表示 1,2+ 表示任何更高的数字。但是,count(distinct productID) 一旦达到 2 就不会停止计算。它会愉快地继续无穷大,然后另一个操作将计算 case。

我已经多次看到同样的事情发生了。

有没有更有效的方法来实现这一点?如果我们只想要 0/1+ 类,答案是半联接(in/exists)。但是任意数量的范围呢?

【问题讨论】:

  • 可能不会。在某些数据库中,count(distinct) 的效率非常低,并且有针对逻辑的变通方法——但它们都没有停在“3”处。但是,据我所知,SQL Server 有一个合理的实现。
  • @GordonLinoff 让您的专家自我说“不”是实现的噩梦......
  • 此查询将扫描和分组orders,因为那是您的分组列的来源。你的聚合表达式是什么并不重要。

标签: sql sql-server tsql query-performance


【解决方案1】:

您可能无能为力。但是这里有两种表达查询的替代方法,可能具有更好的性能。

如果您在“(desiredKeycols, productid)”和可能的“(desiredKeycols, productid desc)”上有索引,您可以尝试:

select desiredKeycols,
       (case distinct_cnt . . . )
from (select o.*,
             (dense_rank() over (partition by desiredKeycols order by productid) +
              dense_rank() over (partition by desiredKeycols order by productid desc)
             ) as distinct_cnt
      from orders o
     ) o
group by desiredKeycols;

这并不止于“3”,但它可能会比count(distinct)优化得更好。

实际上,一个轻微的替代方案将只使用一个索引:

select desiredKeycols,
       (case cnt . . . )
from (select o.desiredKeycols, count(*) as cnt
      from orders o
      group by desiredKeycols, productid
     ) o
group by desiredKeycols;

在某些数据库中,这比count(distinct) 快​​得多。但是,我认为 SQL Server 有更好的优化器,所以它可能不是一个大的胜利。

【讨论】:

    猜你喜欢
    • 2017-11-13
    • 1970-01-01
    • 1970-01-01
    • 2018-08-17
    • 1970-01-01
    • 2014-09-14
    • 2014-02-27
    • 2013-11-23
    • 1970-01-01
    相关资源
    最近更新 更多