2

我使用 SQL Server 2005 编写了一个分页搜索存储过程。它需要许多参数并且搜索条件比较复杂。

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

一方面,我可以编写两个存储过程——一个处理计数,一个处理实际数据,但是我需要在至少两个不同的地方维护搜索逻辑。或者,我可以编写存储过程,以便它接受一个位参数,并在此基础上返回数据或仅返回一个计数。也许用数据填充一个临时表,如果它只是计数,则从中进行计数,否则从中进行选择。这里的问题是可以优化计数过程,因此看起来有很多额外的开销(必须获得不需要的列等)。此外,在存储过程中使用这种逻辑可能会导致错误的查询计划,因为它在两种用途之间来回切换。

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

人们对这些方法有何看法?以前有没有人以我没有想到的方式解决了这个问题?

他们不能从单个呼叫中同时获取结果和计数。

谢谢!

4

6 回答 6

4

我个人使用两个查询方法,是的,您必须在两个地方维护搜索逻辑,但我发现性能优化的好处和代码的整体清洁度最终得到了回报。

使用传递给单个过程的标志是一种潜在的解决方案,但我发现这很难维护,尤其是对于复杂的搜索逻辑。

使用临时表等的路线,只会增加比所需更多的开销。

因此,为什么我用两种查询方法登陆。我在网上找到的所有内容也都推荐这种方法。

于 2008-11-03T15:53:33.670 回答
2

这不是一个正常的问题,您通常希望在获得页面的同时获得总计数。

也就是说,使用两种不同的程序。原因是你有两个非常不同的动作,它们只是表面上相似。

于 2008-11-03T15:52:50.487 回答
2

我确定您已经考虑过这一点:如果数据正在更改 COUNT 并且任何后续的实际分页可能会有所不同(如果添加/删除了行)

你可以有一个用户定义的函数,它返回匹配行的 PK,相对容易做

从 dbo.MyQueryFunction(@Param1,@Param2)中选择计数(*)

得到计数,然后

选择 Col1, Col2, ...
FROM dbo.MyQueryFunction(@Param1, @Param2) AS FN
     加入 dbo.MyTable 作为 T
         ON T.ID = FN.ID
     ... 更多 JOIN ...

获取数据。

不知道这与 Row_Number 在后续分页中的效果如何,但它会保留 MyQueryFunction 中包含的实际“查询逻辑” - 您仍然将在 Sproc 中检索到重复的任何列的所有 JOIN 和功能。

于 2009-11-10T16:32:46.373 回答
1

可能对您的具体问题没有帮助,但 SQL 2005 引入了 Row_Number 函数,该函数便于分页检查

行号示例

比临时表容易得多。

于 2008-11-03T15:55:39.797 回答
1

我发现这个线程正在研究其他东西,并认为我会提到可以通过一个查询返回结果集和记录数。你只需要一个'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;
于 2009-11-10T16:05:26.623 回答
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。

于 2010-11-15T13:17:10.977 回答