`

Sql Server 数据分页

 
阅读更多

1.引言

在列表查询时由于数据量非常多,一次性查出来会非常慢,就算一次查出来了,也不能一次性显示给客户端,所以要把数据进行分批查询出来,每页显示一定量的数据,这就是数据要分页。

2.常用的数据分页方法

我们经常会碰到要取n到m条记录,就是有分页思想,下面罗列一下一般的方法。

我本地的一张表 tbl_FlightsDetail,有300多W记录,主键 FlightsDetailID(Guid),要求按照FlightsDetailID排序 取 3000001 到3000010 之间的10条记录,也是百万级。

方法1 定位法 (利用ID大于多少)

语句形式:

select top 10 * from tbl_FlightsDetail where FlightsDetailID>(
       select max(FlightsDetailID) from ( 
              select top 3000000 FlightsDetailID from tbl_FlightsDetail order by FlightsDetailID
       ) as t
) order by FlightsDetailID

执行计划:

先查出 top 300000,再聚合取这个集合中最大的Id1,再过滤 id大于id1的集合(上图中使用到索引),再取top 10 条。

 

方法2 (利用Not In)


语句形式:

select top 10* from tbl_FlightsDetail where FlightsDetailID not in (
       select top 3000000 FlightsDetailID from tbl_FlightsDetail order by FlightsDetailID
) order by FlightsDetailID

执行计划:

和方法一类似,只是过滤where条件不一样,这里用到的是not in,上图中没有用到索引,耗时8秒。如果 FlightsDetailID不是索引的话,方法1和该方法将差不多。

 

方法3 (利用颠颠倒倒top)

语句形式:

select top 10* from (
       select top 3000010* from tbl_FlightsDetail order by FlightsDetailID
) as t  order by t.FlightsDetailID desc

执行计划:

先取 前面3000010条记录,再倒序,这时再取前面10条即是300001 到300010条记录,没有用到索引,耗时11秒

 

方法4 (ROW_NUMBER()函数)

语句形式:

select * from (
       select *,ROW_NUMBER() OVER (ORDER BY FlightsDetailID) as rank from tbl_FlightsDetail
)  as t where t.rank between 3000001 and 3000010

 执行计划:

Sql 2005版本或以上支持,也没用到索引,耗时2秒,速度还不错。

方法5 (利用IN)

此方法是由 金色海洋(jyk)阳光男孩 回复的,飞常感谢,语句形式:

select top 10 * from tbl_FlightsDetail  where FlightsDetailID in( 
       select top 10 FlightsDetailID from(  
              select top 3000010 FlightsDetailID from tbl_FlightsDetail order by FlightsDetailID
       ) as t order by t.FlightsDetailID desc 
) order by FlightsDetailID

执行计划:

多次执行之后一般维持在4秒左右,用到索引,非常不错,计划图还很长,只截取部分,可能是绕的多一点。

3.千万级分页存储过程

大家百度一下这个标题立马会出现很多相关信息,都大同小异,我自己拷贝的一个,应项目的需要,修改了一个排序的bug以及添加了返回总记录数,如下:

复制代码
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
--分页存储过程  
CREATE PROCEDURE [dbo].[sp_Paging] 
( 
@Tables nvarchar(1000),                --表名/视图名
@PrimaryKey nvarchar(100),             --主键
@Sort nvarchar(200) = NULL,            --排序字段(不带order by)
@pageindex int = 1,                    --当前页码
@PageSize int = 10,                    --每页记录数
@Fields nvarchar(1000) = N'*',         --输出字段
@Filter nvarchar(1000) = NULL,         --where过滤条件(不带where)
@Group nvarchar(1000) = NULL,          --Group语句(不带Group By)
@TotalCount int OUTPUT                 --总记录数
) 
AS  
 
DECLARE @SortTable nvarchar(100) 
DECLARE @SortName nvarchar(100) 
DECLARE @strSortColumn nvarchar(200) 
DECLARE @operator char(2) 
DECLARE @type nvarchar(100) 
DECLARE @prec int 

--设定排序语句
IF @Sort IS NULL OR @Sort = ''     
   SET @Sort = @PrimaryKey      
IF CHARINDEX('DESC',@Sort)>0   
BEGIN         
    SET @strSortColumn = REPLACE(@Sort, 'DESC', '')         
    SET @operator = '<='     
END 
ELSE     
BEGIN                
    SET @strSortColumn = REPLACE(@Sort, 'ASC', '')                
    SET @operator = '>='     
END 
IF CHARINDEX('.', @strSortColumn) > 0     
BEGIN         
    SET @SortTable = SUBSTRING(@strSortColumn, 0, CHARINDEX('.',@strSortColumn))
    SET @SortName = SUBSTRING(@strSortColumn, CHARINDEX('.',@strSortColumn) + 1, LEN(@strSortColumn))     
END 
ELSE     
BEGIN         
    SET @SortTable = @Tables         
    SET @SortName = @strSortColumn  
END 

--设置排序字段类型和精度 
SELECT @type=t.name, @prec=c.prec FROM sysobjects o 
       JOIN syscolumns c on o.id=c.id 
       JOIN systypes t on c.xusertype=t.xusertype WHERE o.name = @SortTable AND c.name = @SortName
        
IF CHARINDEX('char', @type) > 0    
   SET @type = @type + '(' + CAST(@prec AS varchar) + ')'
   
DECLARE @strPageSize nvarchar(50) 
DECLARE @strStartRow nvarchar(50) 
DECLARE @strFilter nvarchar(1000) 
DECLARE @strSimpleFilter nvarchar(1000) 
DECLARE @strGroup nvarchar(1000)  
 
IF @pageindex <1     
   SET @pageindex = 1  
SET @strPageSize = CAST(@PageSize AS nvarchar(50)) 
--设置开始分页记录数 
SET @strStartRow = CAST(((@pageindex - 1)*@PageSize + 1) AS nvarchar(50))  
--筛选以及分组语句
IF @Filter IS NOT NULL AND @Filter != ''     
BEGIN         
    SET @strFilter = ' WHERE ' + @Filter + ' ' 
    SET @strSimpleFilter = ' AND ' + @Filter + ' ' 
END 
ELSE     
BEGIN         
    SET @strSimpleFilter = ''         
    SET @strFilter = ''     
END 
IF @Group IS NOT NULL AND @Group != ''  
   SET @strGroup = ' GROUP BY ' 
--计算总记录数
DECLARE @TotalCountSql nvarchar(1000)
SET @TotalCountSql=N'SELECT @TotalCount=COUNT(*)' +N' FROM ' + @Tables + @strFilter
EXEC sp_executesql @TotalCountSql,N'@TotalCount int OUTPUT',@TotalCount OUTPUT
--执行查询语句    
EXEC(
'
DECLARE @SortColumn ' + @type + '
SET ROWCOUNT ' + @strStartRow + '
SELECT @SortColumn=' + @strSortColumn + ' FROM ' + @Tables + @strFilter + ' ' + @strGroup + ' ORDER BY ' + @Sort + '
SET ROWCOUNT ' + @strPageSize + '
SELECT ' + @Fields + ' FROM ' + @Tables + ' WHERE ' + @strSortColumn + @operator + ' @SortColumn ' + @strSimpleFilter + ' ' + @strGroup + ' ORDER BY ' + @Sort + '
'
)
复制代码

 现在我们来测试一下:

复制代码
DECLARE    @return_value int,
        @TotalCount int

EXEC    @return_value = [dbo].[sp_Paging]
        @Tables = N'tbl_FlightsDetail',
        @PrimaryKey = N'FlightsDetailID',
        @Sort = N'FlightsDetailID',
        @pageindex = 299999,
        @PageSize = 10,
        @Fields = '*',
        @Filter = NULL,
        @Group = NULL,
        @TotalCount = @TotalCount OUTPUT

SELECT    @TotalCount as N'@TotalCount'

SELECT    'Return Value' = @return_value
复制代码

执行计划:

看时间的确是快,执行计划显示4个查询

查询1,是利用系统表获取排序字段、类型和精度,这个很快,全是索引。

查询2,返回总记录数,第一次会慢点,后面就很快了。

查询3 和查询4(用到索引) 才是我们要分页取的数据,查询3 是排序,取一个最大的值赋给变量,查询4是大于这个变量的值 取数据,直接看sql语句,把上面的exec动态语句改成如下:

复制代码
DECLARE @SortColumn varchar(40)
--即 top 3000001,取出最大的 id覆盖@SortColumn 
SET ROWCOUNT  3000001
SELECT @SortColumn= FlightsDetailID  FROM tbl_FlightsDetail ORDER BY FlightsDetailID  
--即 top 10
SET ROWCOUNT 10
SELECT *  FROM  tbl_FlightsDetail  WHERE FlightsDetailID   >= @SortColumn  ORDER BY  FlightsDetailID   
复制代码

你会发现,原来它跟我们标题2 常用的数据分页方法 中的 方法1 定位 类似,原来奥秘在这。

4.小结

还有一些用游标、表变量的那个性能差不作考虑。分页存储过程看起来挺复杂的,语句多,其实都在判断,在左组装,右组装,最终组装成类似 标题2中常用的分页方法中的 的一种语句,掌握了常用的数据分页方法,大家就可以自己写了,当然还有其它的方法,大家可以分享出来。

 

 

原文地址:http://www.cnblogs.com/qqlin/archive/2012/11/01/2745161.html

分享到:
评论

相关推荐

    SQL server 数据分页显示

    总的来说,通过SQL Server和.NET的DATAGRIDVIEW控件实现数据分页显示是一项基础但关键的技能,它涉及到数据库查询优化、用户界面设计以及事件驱动编程等多个方面的知识。理解并掌握这些内容,对于提升你的软件开发...

    千万级数据分页查询存储过程SQLServer

    总的来说,利用SQL Server的存储过程进行千万级数据分页查询,结合合理的索引策略和优化技巧,能够有效提升查询性能,降低系统负载,为用户提供流畅的浏览体验。请参考“分页.txt”和“使用方法.txt”文件,了解更多...

    java 连接sqlserver数据库查询,并分页显示

    String url = "jdbc:sqlserver://localhost:1433;databaseName=myDatabase"; String username = "myUsername"; String password = "myPassword"; try { Class.forName(...

    ASP.NET基于SQLServer的分页

    综上,ASP.NET结合SQL Server的分页技术是构建高效数据展示的重要手段。开发者需要理解分页原理,掌握如何在ASP.NET中使用分页控件,以及如何优化SQL Server的分页查询,以提供流畅的用户体验。在实际项目中,根据...

    关于SQL Server SQL语句查询分页数据的解决方案

    关于SQL Server SQL语句查询分页数据的解决方案 在日常工作中,我们经常需要处理大量数据,并从中获取特定页面的数据。特别是在Web应用开发中,为了提高用户体验,通常会将数据进行分页显示。针对这一需求,本文将...

    Hibernate+sqlserver2000分页

    综上所述,`Hibernate+sqlserver2000分页`是一个结合了ORM框架和数据库分页策略的技术主题。在实际应用中,开发者需要根据业务需求选择合适的分页方法,并注意性能优化,如避免全表扫描,使用索引来加速查询等。理解...

    SQL Server2005分页查询

    在SQL Server 2005中,分页查询是一个常见的需求,特别是在处理大量数据时,为了提高用户体验,通常需要一次性加载一定数量的数据,而不是一次性显示所有数据。以下将详细讲解SQL Server 2005中分页查询的常用方法。...

    sqlserver+group by分组查询分页存储过程

    根据给定的SQL Server存储过程...总之,SQL Server的`GROUP BY`分组查询、存储过程和分页技术都是数据库管理和数据分析中不可或缺的工具。正确理解和灵活运用这些技术,可以极大地提升数据库应用程序的性能和用户体验。

    SQLServer分页.rar

    本资源"SQLServer分页.rar"包含了一个名为"SQL分页.txt"的文件,里面详细讲解了SQL Server中的分页实现方法。 首先,我们来理解SQL Server分页的基本概念。分页通常涉及到两个关键参数:`OFFSET`和`FETCH NEXT`。`...

    sqlserver海量数据TOP分页

    本文将深入探讨如何使用SQL Server中的`TOP`语句来实现高效的数据分页,同时结合JDBC和Servlet技术进行数据的后台处理和前端展示。 首先,`TOP`语句是SQL Server中的一个非常实用的子句,用于在查询结果集中返回...

    sqlserver 实现分页的前台代码 以及后台的sqlserver语句

    在SQL Server中,实现分页查询是数据库应用中常见的需求,尤其在大数据量的展示时,分页可以提高用户体验并优化服务器性能。本教程将详细讲解如何在前端使用Java(假设Test.jsp为JSP页面)和后端使用SQL Server语句...

    SqlServer数据库分页

    在SQL Server数据库中,分页是一种常见的数据检索技术,它允许我们从大量数据中按需获取一部分结果,而不是一次性加载所有记录。这在处理大型数据集时尤其有用,可以提高性能,减少网络传输,以及提供更好的用户体验...

    java语言的分页查询功能(mysql和sql server)

    本教程将详细讲解如何在Java中实现不分框架的分页查询,同时涵盖对MySQL和SQL Server数据库的支持。 一、基础知识 1. 分页概念:分页是将大量数据按一定数量分成若干部分,每次只加载一部分到内存中显示,用户可以...

    海量数据分页sql server经典

    ### 海量数据分页在SQL Server中的实现与优化 #### 概述 在Web应用程序开发中,分页浏览是一项非常重要的功能。特别是在处理大量数据时,如何高效地实现分页变得尤为关键。传统的ADO记录集分页法因其内存占用高、...

    SSH框架+SQLServer实现分页的小项目

    这个"SSH框架+SQLServer实现分页的小项目"提供了一个基础的分页实现示例,适合初学者了解SSH框架如何与数据库交互,以及如何在Java Web应用中实现分页功能。通过研究这个项目,开发者可以学习到SSH框架的整合、...

    SQLserver 分页数据样例

    SQLserver 分页数据样例 只是一个分页数据 查询 比较适合小白

    sql server分页技术(SQL Server 与Access数据库相关分页技术)

    在SQL Server中,分页技术是一项关键功能,尤其在处理大量数据时,它能有效地提高查询性能并优化用户体验。在Web应用中,分页通常用于显示数据库中的数据列表,避免一次性加载所有数据导致的性能问题。以下是几种...

    SQLServer数据库分页查询

    ### SQL Server 数据库分页查询方法详解 #### 一、背景与问题定义 在实际的数据库操作中,分页查询是非常常见的需求之一。对于大型数据集来说,一次加载所有数据到前端显示是不现实的,这不仅会增加服务器负担,还...

    SQL server 分页查询

    SQL Server作为微软推出的一款关系型数据库管理系统,在处理复杂查询、数据分页等方面提供了丰富的功能和优化策略。本文将深入探讨SQL Server中的分页查询技术,帮助读者掌握如何高效地进行数据分页,以提升应用程序...

Global site tag (gtag.js) - Google Analytics