部分计数聚合

Partial count aggregation

注意:虽然我目前的重点是 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,[产品计数分类] 字段将为 return,如果没有关联的 productID,则为 0,对于 1,则为 1,对于任何更高的,则为 2+数字。但是,count(distinct productID)并不会在达到2的时候就停止计算,它会愉快地继续到无穷大,然后再进行一次运算计算这个案例。

我看到同样的事情多次出现。

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

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

如果您有关于“(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 服务器有更好的优化器,所以它可能不是一个大赢家。