建立一个 Web 应用,分页浏览功能必不可少。这个问题是数据库处理中十分常见的问题。经典的数据分页方法是:ADO 纪录集分页法,也就是利用ADO自带的分页功能(利用游标)来实现分页。但这种分页方法仅适用于较小数据量的情形,因为游标本身有缺点:游标是存放在内存中,很费内存。游标一建立,就将相关的记录锁住,直到取消游标。游标提供了对特定集合中逐行扫描的手段,一般使用游标来逐行遍历数据,根据取出数据条件的不同进行不同的操作。而对于多表和大表中定义的游标(大的数据集合)循环很容易使程序进入一个漫长的等待甚至死机。
更重要的是,对于非常大的数据模型而言,分页检索时,如果按照传统的每次都加载整个数据源的方法是非常浪费资源的。现在流行的分页方法一般是检索页面大小的块区的数据,而非检索所有的数据,然后单步执行当前行。
基于游标的一些局限性,ACCP4.0 二期SQL Server课程中去除了游标这部分内容。关于如何使用游标实现分页这里不再叙述。
现在流行的做法是使用子查询来进行分页查询。比如要从数据库中取出从x条到y条的记录,代码如下:
SELECT TOP y-x+1 *
FROM 表名
WHERE (主键 NOT IN
(SELECT TOP x-1 主键FROM 表名)
)
按照上面的思路,我们可以总结出分页查询的公式如下:
SELECT TOP 页大小 *
FROM 表名 WHERE (主键 NOT IN (SELECT TOP 页大小*(页数-1) 主键 FROM表名ORDER BY 排序字段))
ORDER BY 排序字段
按照这个公式,我们可以写出存储过程:
CREATE PROCEDURE pagination
(
@TableName nVARCHAR(4000), --表名
@PageIndex int, --页码
@PageSize int, --每页容纳的记录数
@PrimaryKey VARCHAR(255), --主键(或者有唯一约束的字段)
@SortKey VARCHAR(255) --排序字段
)
AS
­
DECLARE @StrSQL nVARCHAR(4000)
­
SET @StrSQL='SELECT TOP '+CAST(@PageSize AS VARCHAR(20))+' * FROM
'+@TableName+' T WHERE T.'+@PrimaryKey+' NOT IN (SELECT TOP '+CAST((@PageSize*(@PageIndex-1))
AS VARCHAR(20))+' '+@PrimaryKey+' FROM '+@TableName+' ORDER BY '+@SortKey+') ORDER BY '+@SortKey
­
PRINT @StrSQL
­
EXEC SP_ExecuteSql @StrSQL
GO
但这个存储过程有一个致命的缺点,就是它含有NOT IN字样。虽然我可以把它改造为:
SELECT TOP 页大小 *
FROM 表名a WHERE not exists
(select * from (select top (页大小*页数) * from 表名 order by 主键) b where b.主键=a.主键 )
order by 主键
即,用not exists来代替not in,二者的执行效率实际上是没有区别的。既便如此,用TOP 结合NOT IN的这个方法还是比用游标要来得快一些。  虽然用not exists并不能挽救上个存储过程的效率,但使用SQL SERVER中的TOP关键字却是一个非常明智的选择。因为分页优化的最终目的就是避免产生过大的记录集,而我们在前面也已经提到了TOP的优势,通过TOP 即可实现对数据量的控制。  在分页算法中,影响我们查询速度的关键因素有两点:TOP和NOT IN。TOP可以提高我们的查询速度,而NOT IN会减慢我们的查询速度,所以要提高我们整个分页算法的速度,就要彻底改造NOT IN,同其他方法来替代它。
我们知道,几乎任何字段,我们都可以通过max(字段)或min(字段)来提取某个字段中的最大或最小值,所以如果这个字段不重复,那么就可以利用这些不重复的字段的max或min作为分页算法中分开每页的参照物。在这里,我们可以用操作符“>”或“<”号来完成这个使命如:
Select top 10 * from 表名 where id>200
于是就有了如下分页方案:
select top 页大小 *
from 表名
where id>
(select max(id) from
(select top ((页码-1)*页大小) id from 表名 order by id) as T
) order by id
我们可以做这样的测试,以下的三种sql语句得到的结果完全相同,我们可以考察他们的效率。
use pubs
­
select identity(int,1,1) as id,*
into test
from authors
go
­
­
--使用not in查询第二页数据
select top 5 *
from test
where id not in(select top 5 id from test order by id)
order by id
­
­
--使用exists查询第二页数据
select top 5 *
from test a
where not exists(select * from (select top 5 * from test order by id) as b where a.id=b.id)
order by a.id
­
--使用max查询第二页数据
select top 5 *
from test
where id>(select max(id) as id from (select top 5 id from test order by id) as T)
order by id
­
将这三个语句选中后,在查询分析器中选择:查询—〉显示估计的执行计划,得到三个查询的查询成本:查询1与查询2的成本完全一样,查询3的成本比查询1和查询2要低。
在确定了第二种分页方案后,我们可以据此写一个存储过程。下面的存储过程不仅含有分页方案,还会根据页面传来的参数来确定是否进行数据总数统计。
/*****************************************************
存储过程名称:pagination
功能:通用分页
返回值:无
参数:
1.表名(字符串,必要参数)
2.主键或者唯一约束字段(字符串,必要参数)
3.需不需要进行总数统计.(布尔类型,可选参数,默认为1。
1或者true是只统计总条数,不进行查询,  
0或者false进行分页查询,不进行统计)
4.查询条件(字符串,可选参数,默认为无条件查询。
注意不要加where)
5.排序的字段名(字符串,可选参数,默认按照主键排序)
6.页码(整数,可选参数,默认第1页)
7.每页大小(整数,可选参数,默认每页10条记录)
8.排序类型(整数或布尔,可选参数,默认升序排序
1或true按降序排序
0或false按升序排列)
9.需要返回的列(字符串,可选参数,默认返回所有列)
­
author:北大青鸟西安兆隆吴老实
*****************************************************/
CREATE PROCEDURE pagination
@TableName varchar(255), -- 表名
@PrimaryKey varchar(255),--主键或者唯一约束字段
@DoCount bit = 0, -- 需不需要进行总数统计.1是只统计总条数,不进行查询  0进行分页查询,不进行统计
@StrWhere varchar(1500) = '', -- 查询条件 (注意: 不要加 where)
­
@OrderField varchar(255)=@PrimaryKey, -- 排序的字段名,默认按照主键排序
@PageIndex int = 1, -- 页码
@PageSize int = 10, -- 页尺寸
@OrderType bit = 0 ,-- 设置排序类型, 非 0 值则降序
@StrGetFields varchar(1000) = '*'-- 需要返回的列
AS
­
declare @strSQL varchar(5000) -- 主语句
declare @strTmp varchar(110) -- 临时变量
declare @strOrder varchar(400) -- 排序类型
­
/********************************************
@DoCount传递过来的不是0,就执行总数统计
********************************************/
if @DoCount != 0
begin
if @StrWhere!=''
set @strSQL = 'select count(*) as Total from ' + @TableName + ' where '+@strWhere
else
set @strSQL = 'select count(*) as Total from ' + @TableName
end
/********************************************
以下的所有代码都是@DoCount为0的情况:
********************************************/
else
begin
/********************************************
确定是升序还是降序
********************************************/
if @OrderType != 0
begin
set @strTmp = '<(select min'
set @strOrder = 'order by ' + @OrderField +' desc'
end
­
else
begin
set @strTmp = '>(select max'
set @strOrder = 'order by ' + @OrderField +' asc'
end
­
/**********************************************
为了加快执行速度,判断一下是不是第一页
***********************************************/
if @PageIndex = 1
begin
if @strWhere != ''
set @strSQL ='select top ' + str(@PageSize) +' '+@StrGetFields+ ' from ' + @TableName + ' where ' + @strWhere + ' ' + @strOrder
else
set @strSQL ='select top ' + str(@PageSize) +' '+@strGetFields+ ' from '+ @TableName + ' '+ @strOrder
end
/**********************************************
不是第一页
***********************************************/
else
begin
if @strWhere=''
set @strSQL='select top '+str(@PageSize)+' '+@strGetFields+' from '+ @TableName +' where '+@PrimaryKey+@strTmp+'('+@PrimaryKey+') as '+@PrimaryKey+' from (select top '+str((@PageIndex-1)*@PageSize)+' '+@PrimaryKey+' from '+@TableName+' '+@strOrder+') as T) '+@strOrder
else
set @strSQL='select top '+str(@PageSize)+' '+@strGetFields+' from '+ @TableName +' where '+@PrimaryKey+@strTmp+'('+@PrimaryKey+') as '+@PrimaryKey+' from (select top '+str((@PageIndex-1)*@PageSize)+' '+@PrimaryKey+' from '+@TableName+' where '+@StrWhere+' '+@strOrder+') as T) and '+@StrWhere+' '+@strOrder
­
end
­
print @strSQL
end
execute(@strSQL)
欢迎大家批评指正!    

通用高效分页存储过程相关推荐

  1. SQL2005结合ROW_NUMBER()高效分页存储过程

    SQL2005结合ROW_NUMBER()高效分页存储过程: CREATE PROCEDURE [dbo].[sp_Accounts_GetUserListPaged]     @PageIndex ...

  2. oracle如何高效分页,oracle学习之高效分页存储过程实例

    oracle学习之高效分页存储过程实例 时间:2017-07-11 来源: create or replace package p_page is -- Author : PHARAOHS -- Cr ...

  3. oracle万能分页代码,oracle高效分页存储过程代码

    oracle高效分页存储过程代码 create or replace package p_page is -- author : pharaohs -- created : 2006-4-30 14: ...

  4. 【转】通用sqlserver分页存储过程

    单主键: CREATE PROC P_viewPage     /**//*         nzperfect [no_mIss] 高效通用分页存储过程(双向检索) 2007.5.7  QQ:348 ...

  5. 通用sqlserver分页存储过程

    单主键: CREATE PROC P_viewPage/**//*nzperfect [no_mIss] 高效通用分页存储过程(双向检索) 2007.5.7 QQ:34813284敬告:适用于单一主键 ...

  6. mysql 高效分页存储过程_mysql分页存储过程

    CREATE PROCEDURE 'sp_page'( in _pagecurrent int,--/*当前页*/ in _pagesize int,--/*每页的记录数*/ in _ifelse v ...

  7. Oracle高效分页存储过程实例

    create or replace package p_page is -- Author : PHARAOHS -- Created : 2006-4-30 14:14:14 -- Purpose ...

  8. 千万级通用的分页存储过程

    第一个方法: /*   经测试,在 14483461 条记录中查询第 100000 页,每页 10 条记录按升序和降序第一次时间均为 0.47 秒,第二次时间均为 0.43 秒,测试语法如下:   e ...

  9. oracle分页处理实例,Oracle高效分页存储过程实例

    create or replace package p_page is -- Author : PHARAOHS -- Created : 2006-4-30 14:14:14 -- Purpose ...

  10. 高效分页存储过程代码

    -- 获取指定页的数据 CREATE PROCEDURE pagination @tblName varchar(255), -- 表名 @strGetFields varchar(1000) = ' ...

最新文章

  1. 侠客X官方网站成立,第一个内测版本即将放出,敬请期待.
  2. Oracle数据库文件坏块损坏的恢复方法
  3. 机器学习-卷积神经网络简介
  4. 独家 | 一文盘点数据行业的动态演变(附链接)
  5. ajax、offset
  6. 常见汉字Unicode编码
  7. adb可以连接linux设备吗,Linux通过ADB与Android设备交互
  8. 基于weblogic 的EJB 学习笔记-JSP教程,资料/其它
  9. HDU 1874 畅通工程续
  10. foursquare nyc数据集_炫酷的python地理数据可视化
  11. Git教程--如何安装Git 如何高效地使用Git 合理使用Git分支
  12. lbs的核心技术都有哪些?_直击现场 | 腾讯云“揭秘智慧出行核心技术与创新实践”活动完美落幕!...
  13. 智慧酒店客房控制系统开发提高酒店管理效率和服务质量
  14. windows照片查看器无法显示此图片问题
  15. 3个酷到没同学的冷门专业,开始逆袭了?
  16. ue4 中动画控制,利用conduit节点
  17. MATLAB中如何打角标和希腊字母
  18. dodo:人脸识别方法个人见解(包括稀疏表示方法的理解)
  19. 淘宝店铺商品搬家到微店
  20. DarkSiders

热门文章

  1. 电阻、电容、电感、半导体器件的失效分析
  2. 服务器被攻击ip显示国外,服务器被不同的IP攻击怎么破?
  3. Markdown和Latex语法
  4. 利用 bat 脚本强制杀死 Windows 进程
  5. 东芝2000ac废粉盒怎么二次利用_阜新降级组件回收厂家,废太阳能板回收_振昌_光伏...
  6. 基于等效积分形式的近似方法——加权余量法(配点法,伽辽金法)求解微分方程近似解
  7. 计算机语言发展ppt,计算机语言的发展.ppt
  8. LD_PRELOAD实现API劫持
  9. 抽象代数学习笔记四《群:子群、同构、同态》
  10. python与数据挖掘课后实验答案_数据仓库与数据挖掘课后习题答案