【问题标题】:Efficient Paging (Limit) Query in SQLServer 2000?SQLServer 2000 中的高效分页(限制)查询?
【发布时间】:2010-10-04 22:49:54
【问题描述】:

在 SQLServer 2000 中进行分页查询最有效的方法是什么?

“分页查询”相当于在 MySQL 中使用 LIMIT 语句。

编辑:在这种情况下,存储过程是否比任何基于集合的查询更有效?

【问题讨论】:

    标签: sql sql-server-2000 paging limit


    【解决方案1】:

    Paging of Large Resultsets 并且获胜者正在使用 RowCount。还有一个用于更复杂查询的通用版本。 但是要感谢 Jasmin Muharemovic :)

    DECLARE @Sort /* the type of the sorting column */
    SET ROWCOUNT @StartRow
    SELECT @Sort = SortColumn FROM Table ORDER BY SortColumn
    SET ROWCOUNT @PageSize
    SELECT ... FROM Table WHERE SortColumn >= @Sort ORDER BY SortColumn
    

    文章包含完整的源代码。

    请阅读“2004-05-05 更新”信息。 !

    【讨论】:

    • 这假定排序列中的值是唯一的。如果您的排序列中有重复的数据,则此查询可能无法正确执行。假设您的查询是对薪水进行分页,并且您有 35 人赚 4 万美元,40 人赚 5 万美元,20 人赚 6 万美元。如果您使用此解决方案的页面大小为 20,那么您的第二个“页面”将从第 36 行开始,而不是预期的第 21 行。
    【解决方案2】:

    我认为嵌套的SELECT TOP n 查询可能是完成它的最有效方式。

    SELECT TOP ThisPageRecordCount *
    FROM Table
    WHERE ID NOT IN (SELECT TOP BeforeThisPageRecordCount ID FROM Table ORDER BY OrderingColumn)
    ORDER BY OrderingColumn
    

    ThisPageRecordCount 替换为每页的项目,将BeforeThisPageRecordCount 替换为(PageNumber - 1) * items-per-page

    当然,在 SQL Server 2005 中更好的方法是在 CTE 中使用 ROW_NUMBER() 函数。

    【讨论】:

    • 顺便说一句,您需要使用动态 SQL,因为在 2000 年,top 子句中不支持变量和表达式
    【解决方案3】:

    查询的效率实际上取决于底层表的结构。如果,假设您有一个名为 ID 的主键,它是一个 IDENTITY,并且它是一个聚集索引,并且您可以假设没有人对其进行 IDENTITY_INSERT,您可以这样做像这样的查询:

    SELECT TOP XXX FROM table WHERE ID > @LastPagesID;

    这将使您尽快获得结果。其他所有真正有效的东西都是对此的一些变体——也许它不是一个 ID——也许你用来分页的实际上是一个你知道是唯一的日期,但你明白了……此处显示的基于 IN () 的查询可能会起作用,但它们不会影响部分聚集或覆盖索引扫描的性能。

    【讨论】:

      【解决方案4】:

      我认为您真正拥有的是升级到 SQL 2005 的令人信服的理由。

      在 SQL 2005 中,这可以通过以下方式快速轻松地完成:

      select ROW_NUMBER() over (order by [MyField]) as rowNum, *
      from [MyTable]
      where rowNum between @firstRow and @lastRow
      

      如果您真的坚持使用 SQL 2000,我会担心 - 微软不会再完全支持它,因为它现在已经两代了。

      恐怕不会有一种最好的方法来做到这一点 - 所有的解决方案都是黑客攻击。

      @Petar Petrov 的回答可能是最一致的,但是:

      • 如果您要在较小的表上处理聚集索引以进行排序,那么 ASC-DESC 方法(使用 TOP 动态构建两种排序方式)可能更快。
      • 如果您的数据是相对静态的并且您的排序是固定的,那么您可以添加自己的 rowNum 字段,当您更改排序顺序时会更新该字段(听起来很糟糕,但对于大型表来说会很快)。

      我认为您每次都在使用查询分析器进行几个小时的调整。无论哪种方式,存储过程都不会产生太大影响 - 查询计划的缓存不太可能成为瓶颈。

      【讨论】:

        【解决方案5】:

        这是一个通用的 SQL Server 2000 存储过程,它将对任何表执行分页。存储过程接受表的名称、要输出的列(默认为表中的所有列)、可选的 WHERE 条件、可选的排序顺序、要检索的页码和每页的行数。

            CREATE PROCEDURE [dbo].[GetPage]
            @pTableName VARCHAR(30),
            @pColumns VARCHAR(200) = '*',
            @pFilter VARCHAR(200) = '',
            @pSort VARCHAR(200) = '',
            @pPage INT = 1,
            @pPageRows INT = 10
            AS
        
            SET NOCOUNT ON
            DECLARE @vSQL VARCHAR(4000)
            DECLARE @vTempTable VARCHAR(30)
            DECLARE @vRowStart INT
            DECLARE @vTotalRows INT
        
            SET @vTempTable = '##Tmp' + CAST(DATEPART(YYYY, GETDATE()) AS VARCHAR(4)) +
            CAST(DATEPART(MM, GETDATE()) AS VARCHAR(2)) +
            CAST(DATEPART(DD, GETDATE()) AS VARCHAR(2)) +
            CAST(DATEPART(HH, GETDATE()) AS VARCHAR(2)) +
            CAST(DATEPART(MI, GETDATE()) AS VARCHAR(2)) +
            CAST(DATEPART(SS, GETDATE()) AS VARCHAR(2)) +
            CAST(DATEPART(MS, GETDATE()) AS VARCHAR(3))
        
            SET @vSQL = 'SELECT ' + @pColumns + ', IDENTITY(INT, 1, 1) AS ROWID INTO ' + @vTempTable + ' FROM ' + @pTableName
        
            IF @pFilter != '' AND @pFilter IS NOT NULL
            SET @vSQL = @vSQL + ' WHERE ' + @pFilter
        
            IF @pSort != '' AND @pSort IS NOT NULL
            SET @vSQL = @vSQL + ' ORDER BY ' + @pSort
        
            EXECUTE (@vSQL)
        
            -- Get the total number of rows selected
            SET @vTotalRows = @@ROWCOUNT
        
            -- If page number = 0, set it to the first page
            IF @pPage = 0
            SET @pPage = 1
        
            -- If page number is beyond the last page, set page to the last page
            IF (@pPage * @pPageRows) > @vTotalRows
            BEGIN
            SET @pPage = @vTotalRows / @pPageRows
            IF (@vTotalRows % @pPageRows) != 0
            SET @pPage = @pPage + 1
            END
        
            SET @vRowStart = ((@pPage - 1) * @pPageRows) + 1
            SET @vSQL = 'SELECT * FROM ' + @vTempTable + ' WHERE ROWID BETWEEN ' + CAST(@vRowStart AS VARCHAR(10)) +
            ' AND ' + CAST((@vRowStart + @pPageRows - 1) AS VARCHAR(10)) + ' ORDER BY ROWID'
            EXECUTE (@vSQL)
        
            SET @vSQL = 'DROP TABLE ' + @vTempTable
            EXECUTE (@vSQL)
        
        GO
        

        以下是一些关于如何使用 Northwing 数据库的示例:

        EXECUTE [dbo].[GetPage] 'Customers', '*', '', '', 1, 10
        EXECUTE [dbo].[GetPage] 'Customers', '*', '', 'CustomerID DESC', 1, 10
        

        为了确认,这不是我的作品,而是由 http://www.eggheadcafe.com/PrintSearchContent.asp?LINKID=1055

        干杯,约翰

        【讨论】:

          猜你喜欢
          • 2018-07-12
          • 2013-04-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-11-14
          • 1970-01-01
          • 2015-04-16
          相关资源
          最近更新 更多