在SQL Server 2000和2005的数据库应用场景中,当表数据量达到十万甚至百万级别时,传统的分页查询方式比如使用NOT IN或者TOP嵌套查询,会出现明显的性能瓶颈,因此编写高效的分页存储过程是优化查询效率的重要手段。

SQL Server 2000高效分页存储过程实现
SQL Server 2000没有内置的ROW_NUMBER()函数,因此需要借助主键或者唯一索引列来实现高效分页,核心思路是通过两次TOP查询结合排序条件定位目标数据。
以下是一个适配SQL Server 2000的分页存储过程示例,假设分页的表名为TestTable,主键为ID,支持按指定列排序:
-- 创建分页存储过程,适配SQL Server 2000
CREATE PROCEDURE GetPageData_2000
@TableName NVARCHAR(100), -- 表名
@PrimaryKey NVARCHAR(50), -- 主键列名
@OrderColumn NVARCHAR(50), -- 排序列名
@PageSize INT, -- 每页数据条数
@PageIndex INT, -- 当前页码,从1开始
@TotalCount INT OUTPUT -- 输出总数据条数
AS
BEGIN
-- 计算总数据条数
DECLARE @CountSql NVARCHAR(1000)
SET @CountSql = 'SELECT @TotalCount = COUNT(*) FROM ' + @TableName
EXEC sp_executesql @CountSql, N'@TotalCount INT OUTPUT', @TotalCount OUTPUT
-- 计算起始行号
DECLARE @StartRow INT
SET @StartRow = (@PageIndex - 1) * @PageSize + 1
-- 构建分页查询SQL
DECLARE @Sql NVARCHAR(2000)
IF @StartRow = 1
BEGIN
-- 第一页直接查询前N条
SET @Sql = 'SELECT TOP ' + CAST(@PageSize AS NVARCHAR(10)) + ' * FROM ' + @TableName + ' ORDER BY ' + @OrderColumn
END
ELSE
BEGIN
-- 非第一页,先查前N条再取最后M条
SET @Sql = 'SELECT TOP ' + CAST(@PageSize AS NVARCHAR(10)) + ' * FROM ' + @TableName + ' WHERE ' + @PrimaryKey + ' NOT IN ('
SET @Sql = @Sql + 'SELECT TOP ' + CAST((@PageIndex - 1) * @PageSize AS NVARCHAR(10)) + ' ' + @PrimaryKey + ' FROM ' + @TableName + ' ORDER BY ' + @OrderColumn
SET @Sql = @Sql + ') ORDER BY ' + @OrderColumn
END
-- 执行分页查询
EXEC sp_executesql @Sql
END
存储过程调用示例
调用上述存储过程获取TestTable表第2页,每页10条数据,按ID升序排序:
DECLARE @Total INT EXEC GetPageData_2000 'TestTable', 'ID', 'ID', 10, 2, @Total OUTPUT SELECT @Total AS 总数据条数
SQL Server 2005高效分页存储过程实现
SQL Server 2005新增了ROW_NUMBER()窗口函数,可以更简洁地实现分页,不需要依赖主键的唯一性,只需要排序列有明确顺序即可,性能也比2000的实现方式更优。
以下是适配SQL Server 2005的分页存储过程示例:
-- 创建分页存储过程,适配SQL Server 2005
CREATE PROCEDURE GetPageData_2005
@TableName NVARCHAR(100), -- 表名
@OrderColumn NVARCHAR(50), -- 排序列名
@PageSize INT, -- 每页数据条数
@PageIndex INT, -- 当前页码,从1开始
@TotalCount INT OUTPUT -- 输出总数据条数
AS
BEGIN
-- 计算总数据条数
DECLARE @CountSql NVARCHAR(1000)
SET @CountSql = 'SELECT @TotalCount = COUNT(*) FROM ' + @TableName
EXEC sp_executesql @CountSql, N'@TotalCount INT OUTPUT', @TotalCount OUTPUT
-- 构建分页查询SQL,使用ROW_NUMBER()函数
DECLARE @Sql NVARCHAR(2000)
SET @Sql = 'SELECT * FROM ('
SET @Sql = @Sql + 'SELECT *, ROW_NUMBER() OVER(ORDER BY ' + @OrderColumn + ') AS RowNum FROM ' + @TableName
SET @Sql = @Sql + ') AS TempTable WHERE RowNum BETWEEN ' + CAST((@PageIndex - 1) * @PageSize + 1 AS NVARCHAR(10))
SET @Sql = @Sql + ' AND ' + CAST(@PageIndex * @PageSize AS NVARCHAR(10))
-- 执行分页查询
EXEC sp_executesql @Sql
END
存储过程调用示例
调用上述存储过程获取TestTable表第3页,每页15条数据,按CreateTime降序排序:
DECLARE @Total INT EXEC GetPageData_2005 'TestTable', 'CreateTime DESC', 15, 3, @Total OUTPUT SELECT @Total AS 总数据条数
两种实现的对比与注意事项
两种分页存储过程的适用场景和特性对比如下:
| 对比项 | SQL Server 2000实现 | SQL Server 2005实现 |
|---|---|---|
| 依赖函数 | 无特殊函数,依赖主键唯一性 | 依赖ROW_NUMBER()窗口函数 |
| 排序灵活性 | 排序列需要和主键关联,灵活性较低 | 任意排序列均可,灵活性高 |
| 性能表现 | 数据量极大时,NOT IN查询效率下降 | 整体性能更优,适配大表分页 |
| 版本要求 | 仅支持SQL Server 2000及以上 | 仅支持SQL Server 2005及以上 |
使用时需要注意,如果表没有主键,SQL Server 2000的实现方式需要调整为使用所有列的组合唯一条件,避免分页数据重复;SQL Server 2005的实现中排序列如果有重复值,可能会导致分页数据出现偏差,建议排序列搭配唯一列一起排序,比如ORDER BY CreateTime DESC, ID ASC。
分页存储过程的核心是通过减少扫描的数据量来提升效率,实际使用中可以根据业务表的索引情况调整查询逻辑,进一步降低查询耗时。
SQL_Server_2000SQL_Server_2005分页存储过程数据库分页修改时间:2026-07-13 05:33:27