【问题标题】:Top vs Rank/Row Number functions - Which performs higher?Top vs Rank/Row Number 函数 - 哪个性能更高?
【发布时间】:2022-01-18 04:12:40
【问题描述】:

我尝试用 Google 搜索在查询中使用 Top 与使用 Ranking 或 Row_Number 类型函数的成本。

每个功能的成本是否取决于具体情况,或者这两个功能的成本是否可以针对所有情况全面确定?

下面的一些模拟 SQL 使用简单的 CTE 来演示我的问题,如下所示:

WITH fData AS
(
    SELECT 1 AS ID, 'John' AS fName, 'Black' AS lName, CAST('05/19/1975' AS DATE) AS birthDate UNION ALL
    SELECT 2 AS ID, 'John' AS fName, 'Black' AS lName, CAST('04/1/1989' AS DATE) AS birthDate UNION ALL
    SELECT 3 AS ID, 'John' AS fName, 'Black' AS lName, CAST('11/16/1995' AS DATE) AS birthDate UNION ALL
    SELECT 4 AS ID, 'John' AS fName, 'Black' AS lName, CAST('01/16/1968' AS DATE) AS birthDate UNION ALL
    SELECT 5 AS ID, 'John' AS fName, 'Black' AS lName, CAST('01/16/1968' AS DATE) AS birthDate
)   

/* Using TOP 1 vs Row_Number() - Uncomment this and comment the below to VIEW TOP version */
--SELECT TOP 1 d.ID, d.fName, d.lName, d.birthDate
--FROM fData d
--ORDER BY d.birthDate

/* Using the below vs TOP 1 */
SELECT * FROM
(   SELECT d.ID, d.fName, d.lName, d.birthDate, Row_Number() OVER (ORDER BY d.birthDate) AS ranker
    FROM fData d
) r
WHERE r.ranker = 1

使用 TOP 时,无需在其周围应用辅助 Wrapping 查询,它看起来更干净。在应用 Row_Number 或 Ranking 函数后,您必须将其包装以告诉查询您现在想要哪一行...通过应用 WHERE ranker = 1 或 ranker >= 5 来达到与 TOP 1 或 TOP 5 相同的效果。

如果这是可以确定的,哪个更快?

【问题讨论】:

  • 查看查询计划。您会注意到TOP (1) 的查询计划与使用ROW_NUMBERWHERE {ROW_NUMBER()} = 1 相比是完全不同的。 Simple example
  • 它们解决了一个不同的问题 - top 用于当您希望在整个结果集中有一行时。行号用于当您想要每个分区的第一行时。
  • 它当然可以确定(通过执行计划),但要非常小心地得出一般性结论,因为关于构造 X 总是比构造 Y 更快的笼统陈述很少见。查询上下文很重要。 (另外,do not use locale-dependent date formats。)
  • ^^ 嗯,是的,非常正确,但是从没有 TOP 的 Oracle 到现在在 SQL Server 商店……TOP 到处都在使用,很好……但我也可以看到到处都是 Row_Number() 函数,然后或 course 然后用 WHERE ranker = 1 的过滤器包装......所有时间。为什么在 SQL Server 中有 TOP 时使用排名函数?这两个功能解决了相同的问题,而不是我看到它们解决不同的问题。
  • 不能用TOP 替换带有PARTITION BYROW_NUMBER() 子句(或者至少不是没有相当大的困难)。如果您有多个此类订单,则同上;具有多个 ROW_NUMBER()s 的单个查询,您稍后过滤它可能优于使用 TOP 的一组单独的查询。您编写的简单表格确实(实际上)总是在 T-SQL 中使用 TOP 而不是 ROW_NUMBER(),但将 ROW_NUMBER() 添加到语言中是有原因的。

标签: sql-server optimization


【解决方案1】:

在您的示例中,TOP 的效率更高。

TOP 的执行计划如下

TOP NN=1 排序只需要跟踪它所看到的具有最低 birthDate 的行。

对于 row_number 查询,它识别出行号始终是递增的,并且它自己会在计划中添加一个 TOP 1,但它不会将分离的 TOPSORT 组合成一个 TOP N Sort - 所以它对所有 5 行进行完整排序。

如果索引以所需的顺序提供行而不需要排序,那么它就不会太多。 row_number 查询将有两个额外的运算符,无论如何这些运算符都相当便宜。

为什么在 SQL Server 中有 TOP 时使用排名函数

排名功能一般比TOP更强大。

对于两者都可以使用的情况,请考虑TOP 是一种相当古老的专有语法,而不是标准 SQL。在添加窗口功能之前,产品中已经存在很长时间了。如果担心可移植 SQL,则不应使用 TOP

虽然您也可能不会使用排名函数。作为另一个(标准 SQL)替代方案是

SELECT d.ID, d.fName, d.lName, d.birthDate
FROM fData d
ORDER BY d.birthDate
OFFSET 0 ROWS
FETCH NEXT 1 ROW ONLY

给出与TOP 1相同的计划

【讨论】:

  • 这是一个非常人为的例子,因为它是构造表。一个更好的例子可能是将两个真实的表连接在一起。这可能取决于top 1 侧的密度:高密度/低选择性意味着top 1 可能更快,低密度可能排名函数更快。
  • 嗯 - 提出这样一个通用问题的目的不是用 TMI 使问题超载......基本的 CTE 得到了我的感觉。但是为了确保我没有直接询问我的示例中这两个非常基本的查询中哪一个更快......我只是不确定是否有任何关于 TOP 速度的全面信息与一般的排名函数。但似乎更多的是一个情境问题。在这种情况下工作的正确工具。由于在这样一个通用问题上花费了时间和精力,我将其标记为答案。
猜你喜欢
  • 2011-10-06
  • 1970-01-01
  • 2020-03-04
  • 2011-06-12
  • 1970-01-01
  • 1970-01-01
  • 2016-10-08
  • 2010-10-15
  • 2022-01-23
相关资源
最近更新 更多