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
相关推荐
3. Sql Server 2005:这是一个关系型数据库管理系统,提供数据存储、查询和管理功能,支持高效的分页查询。 二、分页实现步骤 1. 数据库设计与准备: - 设计一个包含多行数据的表。 - 在Sql Server 2005中创建并...
除此之外,她还是SQL Server Magazine的优秀编辑和专栏作家,她还写作了大量的SQL Server类书籍,包括著名的Inside Microsoft SQL Server2000。 目录 前言 致谢 引言 第1章 SQL Server 2005 的安装与升级 1.1 ...
本文将深入讲解如何利用博图WinCC V16中的ADODB组件和DataGrid控件来显示来自SQL Server的数据。 ADODB(ActiveX Data Objects Database)是微软提供的一个数据库访问接口,支持多种数据库,包括SQL Server。在...
本主题将深入探讨如何使用JSP(JavaServer Pages)结合SQL Server数据库和Eclipse集成开发环境来实现分页显示数据。以下是关于这个话题的详细讲解。 **一、JSP与Java** JSP是Java平台上的动态网页技术,它允许...
在SQL Server中,报表模板是一种用于呈现和分析数据的有效方式,尤其在企业级的数据管理和决策支持系统中扮演着重要角色。报表可以帮助用户直观地理解数据库中的信息,通过定制化的视图进行数据分析。以下是对SQL ...
SQL Server是一款由微软公司开发的关系型数据库管理系统,广泛应用于企业级数据存储、管理和分析。本课程旨在为初学者提供一个全面了解SQL Server的基础平台,通过学习,你可以掌握数据库系统的核心概念以及SQL ...
在本教程中,我们将聚焦于如何使用C#模拟SQL Server数据库,并结合DataGridView控件来展示数据。首先,我们需要理解几个核心概念: 1. **C#**:这是一种面向对象的编程语言,由微软公司开发,广泛应用于Windows应用...
AspNetPager1是ASP.NET中的一个分页控件,它简化了在Web页面上实现数据分页的过程。开发者无需编写复杂的SQL语句或JavaScript代码,只需要配置一些属性,就可以实现数据的分页显示。AspNetPager1提供了多种样式和...
"基于三层Vs.net+SQLServer2005实现单张表的CRUD(GridView带分页)",这个项目展示了如何使用Microsoft的Visual Studio .NET(Vs.net)开发工具,结合SQL Server 2005数据库管理系统,来创建一个简单的数据管理应用。...
同时,通过缓存、数据分页等技术可以优化性能,提高用户体验。 7. **部署与维护**:项目中包含了.sln文件,这表明项目已经配置好,可以用Visual Studio 2008进行编辑和调试。ASP.NET 和 SQL Server 都支持无缝部署...
4. **数据绑定**:使用GridView、ListView等控件,可以方便地将SQL Server中的数据展示在网页上,支持排序、分页、编辑和删除操作。 5. **存储过程与SQL命令**:通过ADO.NET,可以编写和执行SQL Server的存储过程或...
SQL Server存储过程生成器是一种工具,它旨在帮助数据库管理员和开发人员更轻松、高效地创建和管理存储过程。存储过程是预编译的SQL代码集合,可以在SQL Server中执行,提供了一种组织和重用代码的方式,提高了应用...
在这个博客系统中,SQL Server负责存储所有博客文章、作者信息、评论等数据。开发者可能使用Entity Framework或ADO.NET作为数据访问层,来实现与数据库的交互,进行CRUD(创建、读取、更新和删除)操作。 系统架构...
总的来说,"Ext+sqlserver增删改查简单实例"是一个基础但实用的教程,它帮助初学者理解如何将前端框架与关系型数据库集成,进行基本的数据操作和分页显示。通过深入学习和实践,开发者可以进一步提升Web应用的复杂性...
在本文中,我们将深入探讨如何在Java Spring MVC框架下结合SQL Server数据库以及EasyUI前端库进行数据的增、删、改操作。这对于初学者来说是一个非常实用的学习课题,因为这三者构成了一个基本的Web应用后台开发环境...
为了实现用户界面和数据交互,开发者可能使用了Swing或JavaFX这样的Java GUI库,创建了诸如添加联系人、查找联系人、编辑联系人和删除联系人的功能。这些功能通常涉及事件监听器,当用户触发特定操作(如点击按钮)...
在这个特定的案例中,该系统是用jsp(JavaServer Pages)、Java和Web技术构建的,它与SQL Server 2005数据库进行交互,以存储和检索新闻数据。 **1. JSP(JavaServer Pages)** JSP是Java平台上的一个服务器端脚本...
3. 数据访问层(DAL)设计:介绍如何使用ADO.NET与SQL Server 2005交互,创建数据访问对象(DAO)、数据集(DataSet)、数据适配器(DataAdapter),以及如何实现分页和缓存策略。 4. 业务逻辑层(BLL)设计:讨论...
5. 分页和排序:在处理大量数据时,VB可以利用SQL Server的分页和排序功能,提高查询效率,避免一次性加载所有数据导致性能下降。 6. 安全性:了解如何设置SQL Server的用户权限,确保数据库的安全性。同时,VB代码...
- `SQLHelper.cs`:这是针对SQL Server的数据库操作帮助类,提供了执行SQL语句、存储过程,以及分页查询等功能。 - `OracleHelper.cs`:针对Oracle数据库的操作类,同样支持基本的SQL执行和分页处理。 - `MySql...