获取分页SQL搜索存储过程的计数
我已经使用SQLServer2005编写了一个分页搜索存储过程。它需要许多参数,搜索条件也比较复杂 由于前端架构,我需要能够返回返回的结果数量,而不实际返回结果。然后,前端将再次调用存储过程以获得实际结果 一方面,我可以编写两个存储过程——一个用于处理计数,另一个用于处理实际数据,但是我需要在至少两个不同的位置维护搜索逻辑。或者,我可以编写存储过程,以便它接受一个位参数,并在此基础上返回数据或仅返回一个计数。也许用数据填充一个临时表,若它是count,只需从中进行计数,否则从中进行选择。这里的问题是可以优化计数过程,这样看起来会有很多额外的开销(必须得到不需要的列,等等)。此外,在存储过程中使用这种逻辑可能会导致查询计划不正确,因为它在两种使用之间来回移动 系统中的数据量并不太高(即使是较大的表也只有几百万行)。不过,可能有许多并发用户 人们对这些方法有什么看法?以前有人用我没有想到的方式解决过这个问题吗 他们不能同时从一次呼叫中获取结果和计数获取分页SQL搜索存储过程的计数,sql,tsql,search,stored-procedures,paging,Sql,Tsql,Search,Stored Procedures,Paging,我已经使用SQLServer2005编写了一个分页搜索存储过程。它需要许多参数,搜索条件也比较复杂 由于前端架构,我需要能够返回返回的结果数量,而不实际返回结果。然后,前端将再次调用存储过程以获得实际结果 一方面,我可以编写两个存储过程——一个用于处理计数,另一个用于处理实际数据,但是我需要在至少两个不同的位置维护搜索逻辑。或者,我可以编写存储过程,以便它接受一个位参数,并在此基础上返回数据或仅返回一个计数。也许用数据填充一个临时表,若它是count,只需从中进行计数,否则从中进行选择。这里的问
谢谢 这不是一个正常的问题,您通常希望在获取页面的同时获得总计数
也就是说,使用两种不同的程序。原因是你有两个非常不同的行为,只是表面上彼此相似 我个人赞成双查询方法,是的,您必须在两个地方维护搜索逻辑,但我发现性能优化和代码的整体清洁最终会带来好处 使用传递给单个过程的标志是一个潜在的解决方案,但我发现这很难维护,特别是对于复杂的搜索逻辑 使用临时表等的方法,只会增加比需要更多的开销
因此,为什么我使用了两个查询方法。我在网上找到的所有东西都推荐这种方法 可能对您的特定问题没有帮助,但SQL 2005引入了行数函数,它便于分页检查
比临时表容易得多。我发现这个线程在研究其他内容,我想我应该提到,可以通过一个查询返回结果集和记录计数。您只需要一个“out”参数来携带该值。下面是一个Oracle示例的复制/粘贴,但SQL Server的技术非常类似(我没有访问SQL Server atm的权限) SQL Server最重要的一点是,您可能需要使用row_number()与rownum
procedure get_sample_results (
startrow in number default 1,
numberofrows in number default 10,
whereclause in varchar2,
matchingrows out number,
rc out sys_refcursor
)
is
stmnt varchar2(5000);
endrow number;
begin
stmnt := stmnt || 'select * from table t where 1=1';
if whereclause is not null then
stmnt := stmnt || ' and ' || whereclause;
end if;
execute immediate 'select count(*) from (' || stmnt || ')' into matchingrows;
stmnt := 'select * from (' || stmnt || ') where rownum between :1 and :2';
-- must subtract one to compenstate for the inclusive between clause
endrow := startrow + numberofrows - 1;
open rc for stmnt using startrow, endrow;
end get_sample_results;
我相信您已经考虑过这一点:如果数据正在更改计数,那么任何后续的实际分页都可能不同(如果添加/删除了行) 您可以使用一个用户定义的函数返回匹配行的PKs,这样做相对容易 SELECT COUNT(*) FROM dbo.MyQueryFunction(@Param1, @Param2) 从dbo.MyQueryFunction(@Param1,@Param2)中选择COUNT(*) 数一数,然后 SELECT Col1, Col2, ... FROM dbo.MyQueryFunction(@Param1, @Param2) AS FN JOIN dbo.MyTable AS T ON T.ID = FN.ID ... more JOINs ... 选择Col1,Col2。。。 来自dbo.MyQueryFunction(@Param1,@Param2)作为FN 将dbo.MyTable作为T连接 在T.ID=FN.ID上 ... 更多加入。。。 获取数据
我不知道这与后续分页的行号有多好,但它将保留MyQueryFunction中包含的实际“查询逻辑”-您仍将在存储过程和函数中获取任何列的所有连接。我知道这是一个老问题(已经标记),但是您可以返回一个记录集(也称为结果)并具有一个输出(或多个输出)值,这意味着您只需要一次往返数据库 这是我正在大声思考的事情(已经过了我的就寝时间了…)
嗯。谢谢。这就是我正在使用的东西(或者其他非常类似的东西)。临时表的想法只是为了让我可以在两种方法中使用完全相同的查询来获得结果。否则,我需要控制流逻辑,使我在两个不同的查询需要保持同步。谢谢你的建议。不幸的是,如上所述,前端无法同时获得两个结果,即使是作为输出参数。我昨天生病了,所以我完全错过了这一部分。一个有趣的建议,谢谢。我们已经将代码发布到生产环境中,它的性能很好,所以我不认为我们会在这一点上进行任何更改,但我肯定会在将来记住这一点。如果您阅读之前的评论,请“感谢您的建议”。不幸的是,如上所述,前端无法同时获取两个结果,即使是作为输出参数“所以我认为此解决方案对它们不起作用。请参阅此链接:[使用一个存储过程从表中获取最后N行][1]我认为这可以帮助您。[1]:
CREATE PROCEDURE WhatEver
(
@SomeParam1 NVARCHAR(200),
....
@SomeParam_X INT,
@NumberOfResults INTEGER OUTPUT
)
BEGIN
SET NOCOUNT ON
-- Do your search stuff.
-- ....
SELECT Whatever
FROM WhatWhat
...
-- Ok, the results/recordset has been sent prepared.
-- Now the rowcount
SET @NumberOfResults = @@ROWCOUNT
END