获取分页SQL搜索存储过程的计数

时间:2008-11-03 15:45:12

标签: sql tsql search stored-procedures paging

我使用SQL Server 2005编写了一个分页搜索存储过程。它需要许多参数,搜索条件也相当复杂。

由于前端架构,我需要能够返回返回的结果数量,而不会实际返回结果。然后,前端将再次调用存储过程以获得实际结果。

一方面,我可以编写两个存储过程 - 一个用于处理计数,另一个用于处理实际数据,但是我需要在至少两个不同的位置维护搜索逻辑。或者,我可以编写存储过程,以便它需要一个参数,并根据我返回数据或只是一个计数。也许用数据填充一个临时表,如果计数只是从那里做一个计数,否则从中做一个选择。这里的问题是计数过程可以被优化,因此看起来很多额外的开销(必须得到不需要的列等)。此外,在存储过程中使用这种逻辑可能会导致错误的查询计划,因为它在两次使用之间来回传递。

系统中的数据量不是太高(即使是较大的表也只有几百万行)。可能会有很多并发用户。

人们对这些方法的看法是什么?有没有人以一种我没想过的方式解决过这个问题?

他们不能从一次通话中获取结果并同时计算。

谢谢!

6 个答案:

答案 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)

可能无法解决您的具体问题,但SQL 2005引入了Row_Number函数,这对于分页检查很方便

Row_number example

比临时表更容易。

答案 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。