如何在未编制索引的表上加快基于组的重复计数查询

时间:2012-01-05 10:32:22

标签: sql sql-server

当我需要知道某些列n包含超过c个重复项的行数时,我可以这样做:

WITH duplicateRows AS (
    SELECT COUNT(1)
    FROM [table]
    GROUP BY c
    HAVING COUNT(1) > n
) SELECT COUNT(1) FROM duplicateRows

这会导致不必要的行为:SQL Server会计算按i分组的所有行,这些行(当此表中没有索引时)会导致可怕的性能。

但是,在更改脚本以使SQL Server不必计算所有行时,并不能解决问题:

WITH duplicateRows AS (
    SELECT 1
    FROM [table]
    GROUP BY c
    HAVING COUNT(1) > n
) SELECT COUNT(1) FROM duplicateRows

虽然理论上的SQL Server现在可以在n + 1之后停止计数,但它会导致相同的查询计划和查询成本。

当然,原因是GROUP BY确实引入了成本,而不是计算成本。但我对这些数字并不感兴趣。是否有另一种方法可以在没有索引的表上加快重复行的计数?

4 个答案:

答案 0 :(得分:2)

查询中最大的两个成本是GROUP BY的重新排序(由于缺少适当的索引)以及您正在扫描整个表格。

不幸的是,要识别重复项,重新排序整个表是最便宜的选择。


可能从以下更改中获益,但我非常怀疑它会有多大意义,因为我预计执行计划无论如何都会再次出现。

WITH
  sequenced_data AS
(
  SELECT
    ROW_NUMBER() OVER (PARTITION BY fieldC) AS sequence_id
  FROM
    yourTable
)
SELECT
  COUNT(*)
FROM
  sequenced_data
WHERE
  sequence_id = (n+1)

假设SQLServer2005 +

答案 1 :(得分:1)

没有索引GROUP BY解决方案是最好的,每个基于PARTITION的解决方案都涉及表(clust。索引)扫描和排序,而不是GROUP BY案例中的简单扫描和计数

答案 2 :(得分:1)

如果唯一的目标是确定任何组中是否存在任何行(或者,为了重新说明这一点,“在表中存在重复,给定列c的区别”),添加{{ 1}} TOP(1)查询可以执行一些性能魔术。

SELECT

理论上,SQL Server不需要确定所有组,因此只要找到具有重复的第一个组,查询就会完成(但最坏情况将与原始方法一样长)。我不得不说这是一种有点必要的思考方式 - 不确定它是否正确......

答案 3 :(得分:0)

速度和“没有索引”几乎从不在一起。

虽然这里的其他人已经提到过,但我非常怀疑它会带来性能上的好处。也许您可以尝试使用PARTITION BY重新构建查询。

例如:

WITH duplicateRows AS (
    SELECT a.aFK,
    ROW_NUMBER() OVER(PARTITION BY a.aFK ORDER BY a.aFK) AS DuplicateCount
    FROM Address a
) SELECT COUNT(DuplicateCount) FROM duplicateRows

我没有针对实际的group by子句查询来测试它的性能。这只是建议你如何以另一种方式重组它。