用DataReader 分页与几种传统的分页方法的比较
对于数据库的分页,目前比较传统的方法是采用分页存储过程,其实用 DataReader 也可以实现分页,不需要写存储过程,实现效率上也比几种比较流行的分页方法要略快。
在开始这个方法之前,让我们先创建一个简单的测试环境:
use Test
GO if exists (select * from sysobjects where id = object_id('R_Student') and type = 'u')
drop table R_Student
GO
create table R_Student
(
Id nvarchar(64) Primary Key,
Class nvarchar(64) NOT NULL,
Age tinyint NOT NULL,
Sex tinyint NOT NULL
) GO
Declare
@i int
set @i = 0;
while (@i < 1000000)
begin
insert R_Student values('Name' + Str(@i),'Class' + Str(@i), @i % 100, @i % 2)
set @i = @i + 1
end
通过上述语句创建一个简单的数据表,并插入100万条记录
DataReader 分页的方法:
说出来很简单,见下面程序 源码下载位置
public DataSet RangeQuery(string queryString, long first, long last)
{
try
{
OpenDataReader(queryString); if (first < 0)
{
first = 0;
} for (long i = 0; i < first; i++)
{
if (!_DataReader.Read())
{
return _SchemaDataSet;
}
} if (last < 0)
{
last = 0x7FFFFFFFFFFFFFFF;
} for (long i = first; i <= last; i++)
{
DataRow row = NextRow(); if (row != null)
{
_SchemaTable.Rows.Add(row);
}
else
{
return _SchemaDataSet;
}
} return _SchemaDataSet;
}
finally
{
CloseDataReader();
}
}
其实就是通过DataReader 将当前记录移动到起始页对应的那条纪录,然后再开始读数据。由于之前只是移动记录指针,并不读取
数据,所以效率很高。
几种常用方法介绍
1. 二次 TOP
这种方法效率较低,问题主要处在那个 not in 上面,另外如果Id 是可重复的,得出的结果是
GO
if exists (select * from sysobjects where id = object_id('PagedProc') and type = 'p')
drop procedure PagedProc
GO
create procedure PagedProc
@currentpage int, -- page no
@pagesize int --page size
as
declare
@sqlstr nvarchar(4000) --Query string if @currentpage = 1
begin
set @sqlstr = 'SELECT TOP ' + Str(@pagesize) + '* from r_student order by Id'
end
else
begin set @sqlstr = 'SELECT TOP ' + Str(@pagesize) + ' * from r_student where id not in';
set @sqlstr = @sqlstr + '(SELECT TOP '+ Str((@currentpage-1)*@pagesize) + ' id from r_student order by Id)' end exec (@sqlstr) GO
2. ROWNUMBER
这个方法不受排序字段,以及重复键等的约束,非常通用。效率也不错。说白了,就是先将查询结果存到临时表中,
并为这个临时表提供一个自增长的索引字段,然后根据这个字段进行查询范围。
if exists (select * from sysobjects where id = object_id('PagedProcUseROW_NUMBER') and type = 'p')
drop procedure PagedProcUseROW_NUMBER
GO
create procedure PagedProcUseROW_NUMBER
@currentpage int, -- page no
@pagesize int --page size
as
begin
WITH student AS
(
SELECT *,
ROW_NUMBER() OVER (ORDER BY Id) AS 'RowNumber'
FROM r_student
)
SELECT *
FROM student
WHERE RowNumber BETWEEN (@currentpage-1)*@pagesize + 1 AND (@currentpage)*@pagesize;
end
GO
3. 通用分页存储过程
这个存储过程的出处:
http://www.cnblogs.com/Tracy-Chuang/archive/2006/10/16/530125.html
我稍微改了一点,去掉了一些功能,方便测试。
这个存储过程有一些缺点,比如不支持多字段主键,重复键的处理看似也有问题,不排序也不可以。单纯从效率看,
还是可以的。
if exists (select * from sysobjects where id = object_id('[spCommonPageData]') and type = 'p')
drop procedure [spCommonPageData]
GO
--http://www.cnblogs.com/Tracy-Chuang/archive/2006/10/16/530125.html
-- =============================================
-- Author: <张婷婷>
-- Create date: <2006-08-24>
-- Description: <通用分页存储过程>
-- =============================================
Create PROCEDURE [dbo].[spCommonPageData]
@Select NVARCHAR(500), -- 要查询的列名,用逗号隔开(Select后面From前面的内容)
@From NVARCHAR(200), -- From后的内容
@Where NVARCHAR(500) = NULL, -- Where后的内容
@OrderBy NVARCHAR(100) = NULL, -- 排序字段
@Key NVARCHAR(50), -- 分页主键
@Page INT, -- 当前页 ***计数从1开始***
@PageSize INT -- 每页大小
AS
BEGIN
SET NOCOUNT ON;
Declare @Sql nVarchar(1000), @Sql2 NVARCHAR(500)
--Alter By Tracy.Chuang 2006-08-21更改分页算法,采用比较最大值的方法
Set @Sql=
'Select Top '+Cast(@PageSize As
nVarchar(10))+' '+@Select+ ' From '+@From+ ' Where '+Case
IsNull(@Where,'') When '' Then '' Else @Where+' And ' End+
@Key+' >( Select ISNULL(MAX('+@Key+'), 0) AS MaxID
From (Select Top '+Cast(@PageSize*(@Page-1) As Varchar(10))+'
'+@Key+
' From '+@From+
Case IsNull(@Where,'') When '' Then '' Else ' Where '+@Where End+
' Order By '+@Key+') As T)'+
' Order By '+@Key+Case IsNull(@OrderBy,'') When '' Then '' Else
','+@OrderBy End
Exec(@Sql)
END
四种方法的效率比较。只做了一种条件下测试,其他条件大家有兴趣可以自己测。
PageSize = 10, 记录总数 100万,时间单位为毫秒
| 分页方法 | 第1页 | 第10页 | 第100页 | 第1000页 | 第10000页 | 第100000页 |
| 二次 Top | 4 | 7 | 404 | 28 | 271 | 3926 |
| ROW_NUMBER | 1 | 1 | 2 | 12 | 108 | 3594 |
| 通用分页 | 1 | 1 | 1 | 10 | 82 | 3487 |
| DataReader | 0 | 0 | 1 | 9 | 91 | 3380 |
用DataReader 分页与几种传统的分页方法的比较的更多相关文章
- 从官方文档中探索MySQL分页的几种方式及分页优化
概览 相比于Oracle,SQL Server 等数据库,MySQL分页的方式简单得多了,官方自带了分页语法 limit 语句: select * from test_t LIMIT {[offset ...
- MongoDB实现分页(两种方法)
1.插入实验数据 偷懒用下samus,100条. ; i < ; i++) { Document doc = new Document(); doc["ID"] = i; d ...
- [BS-28] iOS中分页的几种算法
iOS中分页的几种算法 总记录数:totalRecord 每页最大记录数:maxResult 算法一: totalPage = totalRecord % maxResult == 0 ? total ...
- 几种常见SQL分页方式效率比较(转)
http://www.cnblogs.com/iamowen/archive/2011/11/03/2235068.html 分页很重要,面试会遇到.不妨再回顾总结一下. 1.创建测试环境,(插入10 ...
- 查询分页的几种Sql写法
查询分页的几种Sql写法 摘自:http://www.cnblogs.com/zcttxs/archive/2012/04/01/2429151.html 1.创建测试环境,(插入100万条数据大概耗 ...
- 盘点几种数据库的分页SQL的写法(转)
Data序列——盘点几种数据库的分页SQL的写法http://www.cnblogs.com/fireasy/archive/2013/04/10/3013088.html
- 3种SQL语句分页写法
在开发中经常会使用到数据分页查询,一般的分页可以直接用SQL语句分页,当然也可以把分页写在存储过程里,下面是三种比较常用的SQL语句分页方法,下面以每页5条数据,查询第3页为例子: 第一种:使用not ...
- MySQL、SQLServer2000(及SQLServer2005)和ORCALE三种数据库实现分页查询的方法
在这里主要讲解一下MySQL.SQLServer2000(及SQLServer2005)和ORCALE三种数据库实现分页查询的方法. 可能会有人说这些网上都有,但我的主要目的是把这些知识通过我实际的应 ...
- 浅谈js分页的几种方法
一个项目中必然会遇到分页这种需求的,分页可以使数据加载更合理,也让页面显示更美观,更有层次感!那么js分页到底如何实现呢?下面我就来讲一下三种循序渐进的方法 1.自己纯手写分页 更深入的去理解分页的意 ...
随机推荐
- Unity 5.x 导入教学Demo
前言 小巫也来玩Unity3D了.以后会把学习的一些过程博客记录下来,方大家也方便自己学习和查看.本篇博客介绍怎样在Unityclient中导入Assert Store中下载的项目资源,方便我们进一步 ...
- easyUI datagrid 前端假分页
datagrid有两种分页方式,真分页和假分页. 所谓真分页,就是真的每次只获取一张分页的数据. 所谓假分页,就是将所有数据全部获取下来,然后利用其分页控件进行分页. 下面具体说说假分页: 1.dat ...
- tf.float32 implicity
简介 | TensorFlow https://tensorflow.google.cn/programmers_guide/low_level_intro 我们来构建一个简单的计算图.最基本的指 ...
- XMU 1125 越野车大赛 【三分】
1125: 越野车大赛 Time Limit: 500 MS Memory Limit: 64 MB Special JudgeSubmit: 8 Solved: 4[Submit][Statu ...
- html鼠标事件
jsp鼠标事件汇总 onclick 单击时触发的事件,这个比较常用 ondblclick 双击时触发的事件 onmoucedown 鼠标按下时触发的事件(个人觉得与onclick异曲同工) onmou ...
- CSU 1807: 最长上升子序列~ 分类讨论
1807: 最长上升子序列~ Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 138 Solved: 17[Submit][Status][Web Bo ...
- Dinic(模板 再错是不可能的 这辈子都不可能了)
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #inclu ...
- POJ2749 Building road
传送门 这道题真是2-SAT好题啊!!卡了我两个点才做完……垃圾POJ还不告诉我哪错了…… 首先我们先花一段时间把题看懂……(其实是翻译一下),之后我们发现因为每个谷仓只能向一个中转点连边,所以他就是 ...
- iOS开发——多线程
很多朋友都说iOS开发中,最难理解和学习的就是多线程,很多的原理实现都是通过log看到,也比较抽象,本人也是在多线程方面投入过很多脑细胞..无论这方面的知识掌握和应用起来是否轻松,牢固的基本功.正确的 ...
- 7. ExtJS.form中msgTarget
转自:https://www.cnblogs.com/guafuli/articles/msgtarget_values.html Ext表单提示方式:msgTarget:有4中方式:qtip,tit ...