我使用SQL Server 2005编写了一个分页搜索存储过程。它需要许多参数,搜索条件也相当复杂。
由于前端架构,我需要能够返回返回的结果数量,而不会实际返回结果。然后,前端将再次调用存储过程以获得实际结果。
一方面,我可以编写两个存储过程 - 一个用于处理计数,另一个用于处理实际数据,但是我需要在至少两个不同的位置维护搜索逻辑。或者,我可以编写存储过程,以便它需要一个参数,并根据我返回数据或只是一个计数。也许用数据填充一个临时表,如果计数只是从那里做一个计数,否则从中做一个选择。这里的问题是计数过程可以被优化,因此看起来很多额外的开销(必须得到不需要的列等)。此外,在存储过程中使用这种逻辑可能会导致错误的查询计划,因为它在两次使用之间来回传递。
系统中的数据量不是太高(即使是较大的表也只有几百万行)。可能会有很多并发用户。
人们对这些方法的看法是什么?有没有人以一种我没想过的方式解决过这个问题?
他们不能从一次通话中获取结果并同时计算。
谢谢!
答案 0 :(得分:4)
我个人采用两种查询方法,是的,你必须在两个地方维护搜索逻辑,但我发现性能优化的好处和代码的整体清洁最终会得到回报。
使用传递给单个过程的标志是一种潜在的解决方案,但我发现很难维护,特别是对于复杂的搜索逻辑。
使用临时表等的路由,只是增加了比所需更多的开销。
因此,为什么我使用两种查询方法登陆。我在网上找到的所有东西都推荐这种方法。
答案 1 :(得分:2)
这不是正常问题,您通常需要在获取页面的同时计算总计数。
那就是说,使用两种不同的程序。原因是你有两个非常不同的动作,只是表面上相似。
答案 2 :(得分:2)
我确定您已经考虑过:如果数据正在更改COUNT,并且任何后续的实际分页可能会有所不同(如果添加/删除行)
你可以有一个用户定义函数返回匹配行的PK,相对容易做一个
SELECT COUNT(*) FROM dbo.MyQueryFunction(@Param1, @Param2)
获取计数,然后
SELECT Col1, Col2, ... FROM dbo.MyQueryFunction(@Param1, @Param2) AS FN JOIN dbo.MyTable AS T ON T.ID = FN.ID ... more JOINs ...
获取数据。
不知道这与Row_Number在后续分页中的表现如何,但它会保持MyQueryFunction中包含的实际“查询逻辑” - 你仍然要检索任何要检索的列的所有JOIN。 Sproc和功能。
答案 3 :(得分:1)
答案 4 :(得分:1)
我发现这个帖子正在研究别的东西,并且我想提到可以用一个查询返回结果集和记录计数。您只需要一个'out'参数来携带该值。下面是Oracle示例的复制/粘贴,但SQL Server的技术非常相似(我无法访问SQL Server atm)。
SQL Server最重要的是你可能需要使用row_number()vs 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;
答案 5 :(得分:0)
我知道这是一个老问题(已经标记过了),但你可以返回一个记录集(也就是结果)并且有一个OUTPUT(或多个输出)值,这意味着你只需要一次往返数据库
这是我在大声思考的事情(而且它已经过了我的睡觉时间......)
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
HTH。