我有一个程序来返回一个受页码和其他东西限制的结果集。作为OUTPUT参数,我需要根据除页码之外的参数返回所选行的总量。所以我有类似的东西:
WITH SelectedItems AS
(SELECT Id, Row1, Row2, ROW_NUMBER() OVER (ORDER BY Row1) AS Position
FROM Items
WHERE Row2 = @Row2)
SELECT Id, Row1, Row2
FROM SelectedItems
WHERE Position BETWEEN @From AND @To
然后我需要将OUTPUT参数设置为内部查询中的行数。我可以复制查询并对其进行计数,但是这个查询可能会返回数千行(并且将来会更多),所以我正在寻找方法来实现这一点并获得良好的性能。我在考虑表变量,这是个好主意吗?还是其他任何建议?
更具体地说,它是Microsoft SQL Server 2008。
谢谢你,Jan
答案 0 :(得分:19)
您可以使用COUNT(*)将总行数计入主查询中的单独列。像这样:
WITH SelectedItems AS
(SELECT Id, Row1, Row2, ROW_NUMBER() OVER (ORDER BY Row1) AS Position,
COUNT(*) OVER () AS TotalRows
FROM Items
WHERE Row2 = @Row2)
SELECT Id, Row1, Row2
FROM SelectedItems
WHERE Position BETWEEN @From AND @To
这将返回结果集中的计数而不是输出参数中的计数,但这应该符合您的要求。否则,与临时表结合使用:
DECLARE @tmp TABLE (Id int, RowNum int, TotalRows int);
WITH SelectedItems AS
(SELECT Id, Row1, Row2, ROW_NUMBER() OVER (ORDER BY Row1) AS Position,
COUNT(*) OVER () AS TotalRows
FROM Items
WHERE Row2 = @Row2)
INSERT @tmp
SELECT Id, Row1, Row2
FROM SelectedItems
WHERE Position BETWEEN @From AND @To
SELECT TOP 1 @TotalRows = TotalRows FROM @tmp
SELECT * FROM @tmp
您会发现使用临时表只是为了您的分页结果不会占用太多内存(当然,这取决于您的页面大小),并且您只是在短时间内保持活动状态。从临时表中选择完整的结果集并选择TotalRows只需要更长的时间。
这比运行一个完全独立的查询要快得多,在我的测试中(重复WITH)会使执行时间加倍。
答案 1 :(得分:3)
我认为您应该在单独的查询中执行此操作。虽然这两个查询可能看起来几乎相同,但查询优化器处理它们的方式会有很大不同。
从理论上讲,SQL Server可能甚至不会遍历子查询中的所有行来计算它。
答案 2 :(得分:2)
我现在无法访问我的代码库,但我相信您可以使用COUNT()OVER(或类似的命令)来返回作为子查询一部分的总行数。然后,您可以将其作为最终结果集的一部分返回。它在每一行中都是重复的,但对于使用分页的应用程序来说,这是一个小的性能影响,无论如何都应该有限的最终结果。
我会在几个小时后发布确切的代码。
编辑:这是我用来生成计数的行。最后,我们的开发人员想要一个单独的方法来自己获取计数,所以现在我在同一存储过程中的两个位置维护搜索条件。
COUNT(*) OVER (PARTITION BY '') AS TotalCount
将其添加到您的CTE,然后您可以选择TotalCount,它将是您每行中的一列。
答案 3 :(得分:2)
您必须运行整个查询,而不限制范围,至少一次以获得完整的行数。既然你要做到这一点,你应该选择@@ RowCount来输出找到的总行数,而不是在每行中用冗余计数(*)列重载数据读取器。
select YOUR_COLUMNS
from YOUR_TABLE
where YOUR_SEARCH_CONDITION
order by YOUR_COLUMN_ORDERING_LIST;
select @@rowcount;
上面的查询避免了使用冗余COUNT(*)列泛滥SqlDataReader,否则每次调用SqlDataReader()时都会发送该列。 由于您是第一次运行查询...而不是选择范围,只需读取前X行。这样可以提供您想要的结果...完整的结果计数,第一个X记录,以及没有冗余计数列的结果集的高效流式传输。
select YOUR_COLUMNS
from (select YOUR_COLUMNS, ROW_NUMBER()
over(order by BY YOUR_COLUMN_ORDERING_LIST) as RowNum) Results
where Results.RowNum between @From and @To;
在任何情况下,@@rowcount
是在第一次运行查询时访问计数的最直接方式,而不限制结果集(无论如何都要先获得X结果),而不运行单独的count()查询,不使用临时表,也不包括冗余count()列。
答案 4 :(得分:1)
你难道不能将输出变量设置为@@ RowCount吗?这将获得受上次执行语句影响的行:
SELECT stuff FROM mytable
SET @output = @@ROWCOUNT
这应该可以满足您的需求,而不涉及再次运行查询。