SQL存储过程如何避免重复查询同时获取结果与总行数
实现方案
你不需要重复扫描大表,也不需要借助临时表产生额外IO开销,根据你的场景选择对应方案即可:
1. 无分页截断场景:零开销使用@@ROWCOUNT
这是性能最优的方案,没有任何额外查询、没有临时表写入成本。SQL Server会通过系统变量@@ROWCOUNT返回上一条语句的影响行数,你只要保证变量赋值操作紧接在数据查询语句之后即可,中间不能插入任何其他语句(包括变量赋值、日志打印、逻辑判断等,这类语句会重置@@ROWCOUNT的值)。
示例代码:
-- 执行你的带复杂筛选条件的业务查询 SELECT [data] FROM [mytable] WHERE [Condition] -- 紧跟查询语句直接赋值,不要插入其他操作 SET @length = @@ROWCOUNT
注意:如果你的查询用了
TOP、OFFSET/FETCH做结果截断(比如分页只返回前N条),@@ROWCOUNT返回的是实际返回的结果行数,不是符合筛选条件的全量总行数,这类场景用下面的窗口函数方案。
2. 分页/结果截断场景:单次扫描用窗口函数计数
如果你需要在返回部分结果(比如分页数据)的同时拿到全量符合条件的总行数,直接用COUNT(*) OVER()窗口函数,在单次表扫描中同步完成总条数计算,不需要重复查询:
DECLARE @length INT SELECT [data], @length = COUNT(*) OVER() FROM [mytable] WHERE [Condition] -- 你的分页/截断逻辑 ORDER BY create_time DESC OFFSET (@pageIndex - 1)*@pageSize ROWS FETCH NEXT @pageSize ROWS ONLY
执行完成后@length会自动拿到所有符合条件的记录总数,整个过程只对基表做一次扫描,性能远高于重复查询、临时表统计的方案。由于无分区的窗口函数对所有返回行计算的总数值完全一致,即使有多行结果,变量最终拿到的值也是正确的总条数。
3. 结果集复用场景:临时表方案优化
如果你查询出来的结果集后续需要多次参与计算、关联,临时表方案是可行的,但不需要额外对临时表做COUNT查询,同样可以借助@@ROWCOUNT直接拿到插入的行数,减少临时表的扫描开销:
SELECT [data] INTO #temp_mydata FROM [mytable] WHERE [Condition] -- 直接拿插入临时表的行数,不需要执行SELECT COUNT(*) FROM #temp_mydata SET @length = @@ROWCOUNT
注意临时表方案需要把全量结果写入tempdb,数据量较大时会产生明显的IO开销,如果只是为了拿总行数,完全没必要选择这个方案。
内容的提问来源于stack exchange,提问作者Mateen Bagheri
相关产品推荐
相关产品推荐

