0

我想每组得到一行(根据 A 列),这一行应该是该组中“B”值最高的行。顺便说一句,如果需要,(A,B)是唯一的。我编写了以下 sql 代码,它完成了这项工作。我想知道有没有更有效的方法?我更喜欢纯 SQL,但我将在 SQL SERVER 2012 的存储过程中使用它。

DECLARE @mytab TABLE (A INT, B INT, C INT)
INSERT INTO @mytab ( A, B, C ) VALUES (1, 1, 1)
INSERT INTO @mytab ( A, B, C ) VALUES (1, 2, 1)
INSERT INTO @mytab ( A, B, C ) VALUES (1, 3, 1)
INSERT INTO @mytab ( A, B, C ) VALUES (2, 2, 2)
INSERT INTO @mytab ( A, B, C ) VALUES (3, 3, 1)
INSERT INTO @mytab ( A, B, C ) VALUES (3, 2, 2)
INSERT INTO @mytab ( A, B, C ) VALUES (3, 1, 3)
;WITH numbered AS 
(
SELECT *, rn=ROW_NUMBER() OVER (PARTITION BY A ORDER BY B DESC)
FROM @mytab AS m
)
SELECT A, B, C
FROM numbered
WHERE rn=1

返回以下

    A   B   C
    1   3   1
    2   2   2
    3   3   1
4

2 回答 2

2

在我的测试中,使用您的测试数据 x 100,000 行,以下查询的性能提高了 35%。

SELECT A, B, C
FROM @mytab mytab_outer
WHERE B = (SELECT MAX(B) FROM @mytab WHERE A = mytab_outer.A)

如果您查看执行计划,这会胜出,因为对于您的查询,它会将所有时间都花在排序功能上(96%)。

让我对这个问题发疯的是,我认为如果我将您的查询变成一个临时表并为 A 和 B 创建主键(您可以为表变量创建主键——我当时忘记了) ,它会做得更好. 我确保DBCC FREEPROCCACHE在再次测试之前运行。

上述查询的运行速度提高了75 倍,而您的查询的执行时间与以前相同。它没有使用主键创建的聚集索引。即使我为 A 列和 B 列都添加了索引,它仍然没有帮助。我尝试使用表格提示,但无济于事。

因此,从我的测试来看,您的方法似乎是效率最低的方法,尤其是在有索引的情况下。

编辑 所以我想出了为什么使用窗口函数的查询做得这么糟糕。

如果我删除 order by 子句中的方向,那么它会使用我创建的索引,但当然输出是错误的。因此,如果使用表变量,此查询的结果总是很糟糕,因为您无法控制索引的排序方向。

于 2013-07-22T00:31:45.477 回答
0

ROW_NUMBER()在子查询/cte 中使用通常是解决此问题的最佳解决方案。大多数替代方案都需要JOIN,因此性能不佳。

于 2013-07-21T23:48:33.913 回答