【问题标题】:SQL 2005 optimal "Paging"SQL 2005 最佳“分页”
【发布时间】:2010-05-18 12:57:39
【问题描述】:

在使用自定义分页创建记录“网格”时,使用 C# 查询记录总数以及记录开始结束的最佳/最佳方式是什么?

返回分页记录集的SQL:

SELECT Some, Columns, Here FROM (
    SELECT ROW_NUMBER() OVER (ORDER BY Column ASC) AS RowId, *
    FROM
        Records
    WHERE
        (...)
) AS tbl
WHERE ((RowId > @Offset) AND (RowId <= (@Offset + @PageSize)) )

SQL 统计总记录数:

SELECT COUNT(*) FROM Records WHERE (...)

现在,我两次访问服务器:一次用于获取记录,另一次用于计算记录总数。

组合这些查询以避免多次 DB 行程的最佳方式是什么?

【问题讨论】:

    标签: c# .net sql sql-server-2005


    【解决方案1】:

    您可以使用带有输出参数(或返回值)的存储过程来传递总行数。

    create procedure dbo.Stuff_GetAll (
        @StartRowIndex int, -- zero based
        @MaximumRows int
    )
    as
    begin
        declare @TotalRows int
    
        select @TotalRows = count(*) 
        ...
    
        if (@TotalRows > 0 and @MaximumRows > 0)
        begin
            ;with T as (
                select *, row_number() over ()
                ...
            )
            select T.* from T
            where Row between @StartRowIndex + 1 and (@StartRowIndex + @MaximumRows)
        end
    
        return @TotalRows
    end
    GO
    

    您可能希望仅在请求第一页时才向查询 count() 添加检查(可能非常昂贵)。

    【讨论】:

    • 就个人而言,我讨厌使用 SP。他们一直是我维持的噩梦。有没有办法在不创建 SP 的情况下做到这一点?
    • 是的,您可以使用 union 将两个查询组合成一个查询,但这需要动态查询构造(即使我讨厌 SP 对我来说看起来太复杂了 :)。
    • 我正在考虑在“选择”两个表之后使用 NextResult。 like here。但我不知道如何在 C# 中实现这一点。
    • 有趣,从未听说过用 ; 分隔多个 SELECT 的可能性在单个查询中。这是一个伪代码(目前无法测试,抱歉): string query = "select pageddata ... ; select count(*) ..." var command = new SqlCommand(query, conn); IDataReader 阅读器 = command.ExecuteReader(); while (reader.Read()) // 处理行 reader.NextResult(); // 继续 count() 结果 if (reader.Read()) long totalRows = (long)reader[0];
    • 根据我的经验,此解决方案的性能不佳,因为您必须执行两次相同的查询。即,为了填充@TotalRows,您已经执行了两次原始查询(例如,From 子句、Where、cause 等)(一次用于 Count(*),一次在您获得分页结果的 CTE 中)。如果查询非常复杂和/或如果您有大量数据,这将不会很好地执行。
    【解决方案2】:

    我发现最快的方法是返回结果集中的行数:

    With PagedItems As
        (
        Select ...
            , ROW_NUMBER() OVER ( ORDER BY Column ASC ) As Seq
            , ROW_NUMBER() OVER ( ORDER BY Column DESC ) As ReverseSeq
        From Table
        Where ....
        )
    Select ..., ( ReverseSeq + Seq - 1) As TotalRows
    From PagedItems
    Where RowId > @Offeset
        ANd RowId <= ( @Offset + @PageSize )
    

    【讨论】:

    • 不是。虽然看起来非常优雅,但即使您有一个用于 ASC 排序的索引,但实际上 DESC 情况要慢得多。此外,结果集需要在返回的每一行中携带相同的信息。
    • @UserControl - 不要这么认为。系统将单次通过行。在我的测试中,它明显快于临时表或带有 count(*) 的子查询。
    • @UserControl - 此外,每行返回的计数作为列返回是微不足道的。请记住,我们最多只能返回行中的 @PageSize,因此每行额外的 4 个字节不会对性能产生影响。
    • 我敢打赌,SQL Server 2005 可以保证 ASC 和 DESC 排序查询的速度相同(尤其是当您在列上有单个索引时)。实际上,您通常甚至没有您想要排序的列的索引(例如,在网格中免费的用户可选择列排序)。事实上,排序与主题无关,只是排序功能需要它(但不能同时使用 ASC 和 DESC!)以确保我们有一致的结果集。
    【解决方案3】:

    一种方法是将您的查询转换为存储过程,然后有一个输出参数允许您计算总记录数。您将在过程中填充输出参数,然后以与现在相同的方式返回您的记录集。

    【讨论】:

      猜你喜欢
      • 2013-05-25
      • 2011-04-14
      • 1970-01-01
      • 1970-01-01
      • 2010-09-05
      • 1970-01-01
      • 1970-01-01
      • 2010-09-18
      • 2010-10-01
      相关资源
      最近更新 更多