SQLServer 2000中的高效分页(限制)查询?

时间:2009-02-02 15:21:15

标签: sql sql-server-2000 paging limit

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

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

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

5 个答案:

答案 0 :(得分:11)

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”信息。 !

答案 1 :(得分:6)

我认为嵌套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()函数。

答案 2 :(得分:1)

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

SELECT TOP XXX FROM table WHERE ID> @LastPagesID;

这将尽快为您提供结果。其他所有真正有效的东西都是这方面的一些变体 - 也许它不是一个ID - 也许你正在使用的页面实际上是一个你知道独特的日期,但你明白了......此处显示的基于IN()的查询可能会起作用,但它们不会触及部分聚簇或覆盖索引扫描的性能。

答案 3 :(得分:0)

我认为你真正拥有的是升级到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字段,当您更改排序顺序时更新(听起来很糟糕,但对于大型表格会很快)。

我认为你每次都会使用查询分析器调整几个小时。存储过程无论如何都不会产生太大的影响 - 查询计划的缓存可能不是瓶颈。

答案 4 :(得分:0)

这是一个通用的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

干杯,约翰