zoukankan      html  css  js  c++  java
  • SQL Server的两种数据分页方式简析

    一、使用ROW_NUMBER() OVER()方式

    把表中的所有数据都按照一个ROW_NUMBER进行排序,然后查询ROW_NUMBER @StartRow到@MaxRows之间的行记录。

    SET QUOTED_IDENTIFIER ON
    SET ANSI_NULLS ON
    GO
     
    /*
    ** 获取指定页的记录。
    ** 只适用于指定主键@PrimaryKey有唯一值,且@SortExpression中只指定一个字段排序
    **/
    CREATE PROCEDURE [dbo].[Common_GetPageRecords]
        @StartRow INT,   --起始行(从0开始)
        @MaxRows INT,  --每页的最大记录数
        @TableName NVARCHAR(2000),  --表名
        @PrimaryKey NVARCHAR(50),   --主键
        @GetFields NVARCHAR(1000),  --要获取的列
        @SearchConditions NVARCHAR(2000), --搜索条件
        @SortExpression NVARCHAR(100) --排序表达式
        WITH ENCRYPTION
     AS
    
    SET NOCOUNT ON
    
    DECLARE @SQL NVARCHAR(4000), @AscOrDesc NVARCHAR(5)
    
    DECLARE @RecordsCount INT, @SortField NVARCHAR(50), @SortFieldValue NVARCHAR(100), @PrimaryKeyValue NVARCHAR(50)
    
    SELECT @SortExpression = LTRIM(RTRIM(@SortExpression)), @SortField = '', @AscOrDesc = ''
    IF @@ERROR <> 0 
    BEGIN
        ROLLBACK TRANSACTION
        RETURN
    END
    IF @SortExpression <> '' AND @SortExpression <> @PrimaryKey
    BEGIN
        IF UPPER(RIGHT(@SortExpression, 5)) = ' DESC'
        BEGIN
            SELECT @AscOrDesc = ' DESC', @SortField = RTRIM( LEFT(@SortExpression, LEN(@SortExpression) - 5) )
        END
        ELSE 
        BEGIN
            SELECT @AscOrDesc = ''
            IF UPPER(RIGHT(@SortExpression, 4)) = ' ASC'
                SELECT @SortField = RTRIM( LEFT(@SortExpression, LEN(@SortExpression) - 4) )
            ELSE
                SELECT @SortField = @SortExpression
        END
    END
    
    SET @SearchConditions = @SearchConditions + CASE WHEN @PrimaryKey = '' THEN '' ELSE CASE WHEN @SearchConditions = '' THEN '' ELSE ' AND ' END +  @PrimaryKey + ' >= -1' END
    
    IF @MaxRows = -1
    BEGIN
        SET @SQL = 'SELECT ' + @GetFields + ' FROM ' + @TableName + 
             CASE WHEN @SearchConditions = '' THEN '' ELSE ' WHERE (' + @SearchConditions + ')' END + 
            ' ORDER BY ' + CASE WHEN @SortField = '' THEN @PrimaryKey ELSE 
                        CASE WHEN @SortField = @PrimaryKey THEN @SortExpression ELSE @SortExpression + ', ' + @PrimaryKey END
            END
        EXECUTE (@SQL)
    END
    ELSE
    BEGIN
        SET @StartRow = @StartRow + 1
        
        SET ROWCOUNT @StartRow
            
        SET @SQL = 'SELECT @PrimaryKeyValue = ' + @PrimaryKey + 
            CASE WHEN @SortField = '' OR @SortField = @PrimaryKey THEN '' ELSE ', @SortFieldValue = CONVERT(NVARCHAR(100), ' + @SortField + ', 121)'  END + 
        ' FROM ' + @TableName + (CASE WHEN @SearchConditions = '' THEN '' ELSE ' WHERE ' + @SearchConditions END) + 
        ' ORDER BY ' + CASE WHEN @SortField = '' THEN @PrimaryKey ELSE 
                    CASE WHEN @SortField = @PrimaryKey THEN @SortExpression ELSE @SortExpression + ', ' + @PrimaryKey END
        END
        EXECUTE SP_EXECUTESQL @SQL, N'@PrimaryKeyValue NVARCHAR(50) OUTPUT, @SortFieldValue NVARCHAR(100) OUTPUT', 
            @PrimaryKeyValue OUTPUT, @SortFieldValue OUTPUT
    
        SET ROWCOUNT @MaxRows
    
        SET @SQL = 'SELECT ' + @GetFields + ' FROM ' + @TableName + 
            ' WHERE (' + CASE WHEN @SortField = '' OR @SortField = @PrimaryKey 
                THEN @PrimaryKey + (CASE WHEN @AscOrDesc = '' THEN ' >= ' ELSE ' <= ' END) + @PrimaryKeyValue
                ELSE @SortField + (CASE WHEN @AscOrDesc = '' THEN ' > ' ELSE ' < ' END) + '''' + @SortFieldValue + ''' OR (' + @SortField + ' = ''' + @SortFieldValue + ''' AND ' + @PrimaryKey + ' >= ' + @PrimaryKeyValue + ')'
                END + ')' + CASE WHEN @SearchConditions = '' THEN '' ELSE ' AND (' + @SearchConditions + ')' END + 
            ' ORDER BY ' + CASE WHEN @SortField = '' THEN @PrimaryKey ELSE 
                        CASE WHEN @SortField = @PrimaryKey THEN @SortExpression ELSE @SortExpression + ', ' + @PrimaryKey END
            END
        EXECUTE (@SQL)
    
        SET ROWCOUNT 0
    END
    
    SET @SQL = 'SELECT @RecordsCount = COUNT(1) FROM ' + @TableName + (CASE WHEN @SearchConditions = '' THEN '' ELSE ' WHERE ' + @SearchConditions END)
    EXECUTE SP_EXECUTESQL @SQL, N'@RecordsCount INT OUTPUT', @RecordsCount OUTPUT
    
    SET NOCOUNT OFF
    RETURN @RecordsCount
    GO

    执行语句示例:

    EXEC [Common_GetPageRecords] @StartRow = 0,              
                                 @MaxRows = 200,             
                                 @TableName = N'Customers',
                                 @PrimaryKey = N'CustomerID',
                                 @GetFields = N'CustomerID,CustomerNumber,CustomerName,CustomerCity',
                                 @SearchConditions = N'CustomerID>1220',  
                                 @SortExpression = N'CustomerID asc';  

    二、使用OFFSET FETCH NEXT方式(SQL2012以上的版本才支持:推荐使用 )

    使用OFFSET是SQLServer2012新具有的分页功能,主要功能是从第x条数据开始共取y数据,但是其必须根再Order By后面使用。

     SELECT * FROM [dbo].[Customers] ORDER BY customerid asc OFFSET 0 ROWS FETCH NEXT 200 ROWS ONLY

    三、综合比较

    在 Sql Server 2012及以上版本里面,分页方法中,Offset and FetchROW_NUMBER() 比较起来,无论是性能还是语法,都是有优势的。

    但是性能方面,优势并不是太大,两者的IO 消耗完全相同,只是在CPU 方面,Offset and Fetch 方面要好一些,但是不明显。如果对于一个每秒都要处理成千上万条的分页Sql语句的DB 来说,Offset and Fetch 在CPU 方面的优势会比较明显的,否则,性能的提升并不明显。

    语法方面 Offset and Fetch 则是十分的简洁,一句搞定,比起 Row_Number() 好了太多 ~
    同是 Offset and Fetch 并不仅仅可以用来分页哦,具体其他使用,大家可以自行参考 MSDN

  • 相关阅读:
    PAT——1069. 微博转发抽奖
    PAT——1068. 万绿丛中一点红
    PAT——1066. 图像过滤
    PAT——1065. 单身狗
    PAT——1064. 朋友数
    PAT——1063. 计算谱半径
    PAT——1062. 最简分数
    PAT——1061. 判断题
    PAT——1060. 爱丁顿数
    PAT——1059. C语言竞赛
  • 原文地址:https://www.cnblogs.com/sgxw/p/13890169.html
Copyright © 2011-2022 走看看