【发布时间】:2018-02-24 22:52:05
【问题描述】:
我们目前使用的是 SQL Server 2016。根据 Microsoft 页面 Deprecated Database Engine Features in SQL Server 2016,SET ROWCOUNT 已被弃用。所以我们试图将所有SET ROWCOUNT N 语句转换为TOP(N) 语句。看起来很简单,但是我们遇到了一个情况,N是存储过程中的参数,默认为0。
所以在旧代码中,它类似于SET ROWCOUNT @NumRows。如果@NumRows 为0,则表示关闭SET ROWCOUNT 选项,因此以下查询将返回所有行。但是如果我们将其转换为TOP(@NumRows),这意味着它将返回 0 行。为了避免这个问题,我们可以添加额外的 IF 条件,如果 @NumRows 为 0,则将 @NumRows 设置为一个巨大的数字。或者我们可以添加额外的 IF 条件,如果 @NumRows 为 0,那么我们使用不带 TOP 的 SELECT,否则我们照常使用 SELECT TOP(N)。
但是这些解决方案中的任何一个都会在存储过程中添加额外的代码,所以我的问题是:考虑到 N 可能为 0,有没有一种优雅的方法可以将 SET ROWCOUNT N 转换为 TOP (N)?
更新:添加存储过程模板
-- Default to 0, in this case, SET ROWCOUNT 0 will return all result
-- But if we change it to TOP(@rows), it returns no result.
CREATE PROCEDURE Proc1
@rows int = 0
AS
SET ROWCOUNT @rows
SELECT Col1 FROM table1
ORDER BY Col2
SET ROWCOUNT 0
-- In this case, the default is not 0
-- But the program that calls this stored procedure could pass in value 0.
-- We also don't want to change default value for this stored procedure.
-- So I think in this case, we may have to add IF @rows = 0, SET @rows = huge_number
CREATE PROCEDURE Proc2
@rows int = 10
AS
SET ROWCOUNT @rows
SELECT Col3 FROM table2
ORDER BY Col4
SET ROWCOUNT 0
【问题讨论】:
-
优雅?不,但是您可以在将其插入您的
top子句之前说select @NumRows = iif(@NumRows = 0, 2147483648, @NumRows)。也就是说,这很可能会给您带来糟糕的查询计划。除非您有数千个需要查找/替换的过程,否则您可能需要考虑指定两个不同代码路径的额外工作。您的里程可能会有所不同。 -
我会警告不要使用多个执行路径。它会导致非常有趣的性能问题。 Gail Shaw 在这里有一篇关于这个主题的精彩博文。 sqlinthewild.co.za/index.php/2009/09/15/…
-
@SeanLange 感谢您的链接。我通读了它并理解了不同执行计划的可能性。因此,如果我不使用不同的执行路径,那意味着我将始终使用
TOP(N)。然后我需要检查N值是否为0。如果为0,我可以从表中生成NumRows= 2147483647 或NumRows= count(*),这对查询计划有什么影响? -
SET ROWCOUNT不推荐用于SELECT语句,仅适用于 INSERT、UPDATE 和 DELETE
标签: sql-server tsql sql-server-2016 sql-limit