破宝

我是一块破破烂烂的宝贝石头。
随笔 - 94, 评论 - 1281, 引用 - 52

导航

关于

自选精华版 RECOMMENDATIONS
留言板 GUESTBOOK

本人 blog 文章、图片及其他资源等,除另有声明外,均遵循以下原则向全球(当然包括朝鲜、古巴、利比亚等国)共享:

1。欢迎转载、复制、传播、引用,但转载、复制(包括但不仅限于作为参考资料复制到本地)、传播、引用同时必须在显著位置注明作者(破宝/percyboy)和文章原始 URL 地址等信息。但商业转载、复制、传播(尤指用于图书、光盘等媒体的部分或全部),须事先征得本人的许可。

2。文章以“现状”提供,不为由于使用本站资源而造成的任何损失而负责,仅提供力所能及的咨询和参考意见。

3。关于修改:允许您将本 blog 中的资源作为参考资料复制时的一定修改,但仍须保留作者和出处信息;其他情况下的修改(包括修改后再发布),须和本人确认许可。
 

标签

每月存档

最新留言

广告

 

虽然 DataGrid 控件自己带了一个分页处理机制,但它是将符合查询条件的所有记录读入内存,然后进行分页显示的。随着符合条件的记录数目增多,就会出现运行效率问题,或者至少是资源的利用率下降。

下面的代码示例都以下面的表结构为准:

 

  Articles 表 SQL Server 类型 Oracle 类型
PK Id int (自增) number(9) (插入时在当前最大值上加1)
  Author nvarchar(10) nvarchar2(10)
  Title nvarchar(50) nvarchar2(50)
  PubTime datetime date

SQL Server / Access 等微软产品中,我们通常的自定义分页有两种思路:

一种是以 ASP.NET Forum 为代表的、“临时表”方法:即在存储过程中建立一个临时表,该临时表包含一个序号字段(1,2,3,....)以及表的主键(其他能够唯一确定一行记录的字段也是可以的)字段。存储过程可能如下:(编号 SS1)

CREATE Procedure GetAllArticles_Paged
(
     @PageIndex int,
     @PageSize int,
     @TotalRecords out int,
     @TotalPages out int
)
AS

DECLARE @PageLowerBound int
DECLARE @PageUpperBound int

-- Set the page bounds
SET @PageLowerBound = @PageSize * @PageIndex
SET @PageUpperBound = @PageLowerBound + @PageSize + 1

-- Create a temp table to store the select results
CREATE TABLE #tmp
(
     RecNo int IDENTITY (1, 1) NOT NULL,
     ArticleID int
)

INSERT INTO #tmp
     SELECT [ID]
     FROM Articles
     ORDER BY PubTime DESC

SELECT A.*
FROM Articles A (nolock), #tmp T
WHERE A.ID = T.ArticleID AND
     T.RecNo > @PageLowerBound AND
     T.RecNo < @PageUpperBound
ORDER BY T.RecNo

GO

另一种可能更适合程序中“拼凑” SQL 语句:用两次 TOP 命令取得我们所要的分页数据,例如:(编号 SS2)

SELECT * FROM
     (
     SELECT TOP(PageSize) * FROM
     (
          SELECT TOP (PageSize * PageIndex) *
          FROM Articles
          ORDER BY PubTime DESC
     )
     ORDER BY PubTime ASC
)
ORDER BY PubTime DESC

这个的想法就是“掐头去尾”,还有不少分页的方法,这里就不一一列出了。

对于 Oracle 数据库,有几处不同严重妨碍了上面几个方法的实施,比如,Oracle 不支持 TOP 关键字:不过这个好像并不十分严重,因为它提供了 rownum 这个隐式游标,可以实现与 TOP 类似的功能,如:

SELECT TOP 10 ... FROM WHERE ...

要写成

SELECT ... FROM ... WHERE ... AND rownum <= 10

rownum 是记录序号(1,2,3...),但有一个比较麻烦的事情是:如果 SQL 语句中有 ORDER BY ... 排序的时候,rownum 居然是先“标号”后排序!这样,这个序号如果不加处理是不合乎使用需求的。

至于临时表,Oracle 的临时表和 SQL Server 的有很大不同,我还没搞懂这个东西,就不妄加揣测了。

国内网站中介绍 Oracle 分页的资料很少,我找到了一个国外站点(www.faqts.com)的一篇 FAQ,根据这篇文章的介绍,可以如下分页:(编号 Ora1)

SELECT * FROM
     (
     SELECT A.*, rownum r
     FROM
          (
          SELECT *
          FROM Articles
          ORDER BY PubTime DESC

          ) A
     WHERE rownum <= PageUpperBound
     ) B
WHERE r > PageLowerBound;

其中蓝色部分可以改为任意的、需要的 SQL SELECT 语句,这点倒是挺方便的。

 

有兴趣的朋友可以接着谈谈你们的想法和算法,期待中……(为了方便说话,上面三个已经加上编号。大家贴算法时也可以按此序加上编号,方便讨论。)

打印 | 张贴于 2004-09-14 21:17:00 | Tag:暂无标签

留言反馈

#回复: 分页(Paging) / SQL Server / Oracle 编辑
谢谢各位高手指教!刚好解决目前我的问题,呵呵
2008-01-17 16:56:00 | [匿名用户:新手]
#回复: 分页(Paging) / SQL Server / Oracle 编辑
如果用rownum的话,数据有1000万条的时候,那么查最后几页和查第一页的效率我认为肯定不同的啊,因为其子查询一个是返回1000万条左右的数据,一个是返回10几行的数据,这个问题怎么解决呢?
2007-12-06 11:23:00 | [匿名用户:路人]
#回复: 分页(Paging) / SQL Server / Oracle 编辑
正好今天代码中碰到了需要使用分页,考虑优化,上来查资料,版主的方法不错,不过有人提到内联SQL不知道如何写,才能提高性能。
版主的这种 ORACLE 分页方式,越到后面应该会越慢的,根据执行计划看COST,BYTES,CPU都逐渐递增的。

to 高材生:应该用版主这种WHERE写法,第一步先要限制ROWNUM,才能尽量减小COST,BYTES,CPU,这在前几页的效能都将是您那种最后才一起写ROWNUM的几十倍,虽然你那么写看上去比较舒服。只有在最后一个分页,计划成本才会和您的那个一致。
2007-10-08 06:50:00 | [匿名用户:学生一族]
#分页(Paging) / SQL Server / Oracle 编辑
虽然 DataGrid 控件自己带了一个分页处理机制,但它是将符合查询条件的所有记录读入内存,然后进行分页显示的。随着符合条件的记录数目增多,就会出现运行效率问题,或者至少是资源的利用率下降。
2007-09-20 17:08:00 | [匿名用户:Nuke'Blog]
#回复: 分页(Paging) / SQL Server / Oracle 编辑
哈哈,以我多年的数据经验可以非常肯定地告诉大家oracle中的指定页是非常高效的!!,而access与sqlserver,根本就是垃圾。当数据表记录达到万以上数量级后,后者的分页根本就是无法接受的。所以对于大型开发,一定要用oracle哦!!
oracle中的写法跟楼主的差不多,也可以稍微换个写法:
SELECT * FROM
(
SELECT A.*, rownum r
FROM
(
SELECT *
FROM Articles
ORDER BY PubTime DESC
) A
) B
WHERE r <= PageUpperBound
and r > PageLowerBound;
===========================================
至于sqlserver以及access中,可就慢多了,如果表数据量大的话,估计要用存储过程。否则根本不能用。
写法也如版主那样。
2007-05-22 15:29:00 | [匿名用户:高材生]
#datalist 分页(转) 编辑
目前datalist分页的主要方式有两种,一种是利用sql分多次读出数据,对于大数据量来说效率比较高,同时也有多种方案主要是这两篇文章里面写的sql储存过程分页大比拼和分页另外一种是利用SqlData...
2007-04-27 22:15:00 | [匿名用户:风轻如梦]
#【转】分页(Paging) / SQL Server / Oracle 编辑
分页(Paging)/SQLServer/Oracle .pbcode{font-size:10pt;background-color:#eeeeee;margin:10px...
2007-01-05 00:06:00 | [匿名用户:mbskys]
#re: 分页(Paging) / SQL Server / Oracle 编辑
To 剑气:那只是因为查询的效率把??对于分页来说应该算OK的!!
2006-11-10 08:47:00 | [匿名用户:ANDY]
#re: 分页(Paging) / SQL Server / Oracle 编辑
楼主使用Ora1的效率肯定低下,在子查询里应该添加限制条件
2006-11-09 16:28:00 | [匿名用户:剑气]
#re: 分页(Paging) / SQL Server / Oracle 编辑
SELECT * FROM
(
SELECT TOP(PageSize) * FROM
(
SELECT TOP (PageSize * PageIndex) *
FROM Articles
ORDER BY PubTime DESC
)
ORDER BY PubTime ASC
)
ORDER BY PubTime DESC

这种GP方法还在传,翻最后一页准错!!(当最后一页的记录不等于PageSize )
2006-10-25 13:32:00 | [匿名用户:aa]
#re: 分页(Paging) / SQL Server / Oracle 编辑
oracle:
select * from table where rowid not in(select rowid from table where rownum<=200) and rownum<=100;
从201条开始读取100条,不过排序问题就麻烦了!
2006-07-12 15:49:00 | [匿名用户:翔]
#re: 分页(Paging) / SQL Server / Oracle 编辑
to: SunLight
你那个最主要先是查询的效率问题. 然后才是分页问题.
2006-05-08 18:06:00 | [匿名用户:simple.world.cn]
#re: 分页(Paging) / SQL Server / Oracle 编辑
SELECT * from
(select * from tab where seg1>=1000 order by seg1) where rownum<50
2005-11-28 16:19:00 | [匿名用户:asciiart]
#re: 分页(Paging) / SQL Server / Oracle 编辑
from (select * from table order by key )
??
2005-11-10 17:48:00 | [匿名用户:niming]
#re: 分页(Paging) / SQL Server / Oracle 编辑
那么在Oracle中怎么解决同时使用rownum和order by这个问题呢?
2005-09-30 09:46:00 | [匿名用户:山伟]
#re: 分页(Paging) / SQL Server / Oracle 编辑
SELECT * FROM
(
SELECT A.*, rownum r
FROM
(
SELECT *
FROM Articles
ORDER BY PubTime DESC
) A
WHERE rownum <= PageUpperBound
) B
WHERE r > PageLowerBound;

这种方式查大数据的时候每改变一个分页的时候,速度都很慢,建议大数据时候慎用此方法
2005-09-29 17:27:00 | [匿名用户:yy]
#re: 分页(Paging) / SQL Server / Oracle 编辑
oracle 我只知道这样分,不知道效能怎么样
select * from table where rownum<60
minus
select * from table where rownum<50;

2005-09-26 22:33:00 | [匿名用户:路人]
#re: 分页(Paging) / SQL Server / Oracle 编辑
to 破宝:
我也这么想过,但问题是我这里是按查询条件进行数据查询
2005-07-14 15:41:00 | [匿名用户:SunLight]
#re: 分页(Paging) / SQL Server / Oracle 编辑
to SunLight:
如果有那么大的数据量,就应该像别的办法,比如专门加个字段记录排序位次,
或者间专门的表记录排序位次。我是这么想的。
2005-07-14 15:22:00 | [匿名用户:破宝]
#re: 分页(Paging) / SQL Server / Oracle 编辑
请教一下,我现在有一个日产生数据达400万左右的历史数据查询,基于B/S+Oracle,不知道有没有好的分页模式,我觉得用楼主的做法,好象查询出来的数据随着页码的增大,速度却成倍成倍的变慢,很容易出现操作超时
2005-07-14 15:18:00 | [匿名用户:SunLight]
#re: 分页(Paging) / SQL Server / Oracle 编辑
不错,正好帮我解决了oracle下的分页问题!
2005-07-12 15:50:00 | [匿名用户:nayij]
#re: 分页(Paging) / SQL Server / Oracle 编辑
那在SQL SERVER 如何实现Oracle的ROWNUM功能呢?
2005-06-30 14:31:00 | [匿名用户:wangjing]
#re: 分页(Paging) / SQL Server / Oracle 编辑
我常用的方法是
SELECT TOP pagesize *
FROM articles
WHERE id NOT IN ( SELECT TOP ( pagesize * pageindex ) id FROM articles ORDER BY id DESC )
ORDER BY id DESC
2005-05-23 18:42:00 | [匿名用户:鱼蛋]
#re: 分页(Paging) / SQL Server / Oracle 编辑
2005-04-07 15:12:00 | [匿名用户:孙航]
#分页(Paging) / SQL Server / Oracle 编辑
Ping Back来自:blog.csdn.net
2005-01-22 18:03:00 | [匿名用户:morepower]
#分页(Paging) / SQL Server / Oracle (转) 编辑
Ping Back来自:blog.csdn.net
2005-01-20 15:49:00 | [匿名用户:vscn]
#re: 分页(Paging) / SQL Server / Oracle 编辑
The following query itself actually is slower than the inner query itself in database. You can figure this out by looking at the query plan in TOAD or SQLNavigator. The benefit you get though is your application only needs to fetch a subset of results from the database to application server or client. If you are using Java, there is a generic way to achieve the same result by calling java.sql.Statement.setMaxResults(25).

SELECT * FROM
(
SELECT A.*, rownum r
FROM
(
SELECT *
FROM Articles
ORDER BY PubTime DESC
) A
WHERE rownum <= PageUpperBound
) B
WHERE r > PageLowerBound;
2004-10-10 06:39:00 | [匿名用户:李白]
#re: 分页(Paging) / SQL Server / Oracle 编辑
全部装载信息放到内存中可行否,速度最快了。
我做了一个用session存储记录集的,份页显示零等待。
2004-09-16 11:58:00 | [匿名用户:塞北的雪]
#re: 分页(Paging) / SQL Server / Oracle 编辑
冗余的分页信息?能不能讲一讲具体实现
2004-09-15 13:02:00 | [匿名用户:asdf]
#re: 分页(Paging) / SQL Server / Oracle 编辑
同意怡红公子的在数据中构造一些冗余的分页信息,是性能最好的方法
我在自己的程序中是用这种方法来处理的
临时表的那个处理也有这个意思
2004-09-15 10:27:00 | [匿名用户:albertmozart]
#re: 分页(Paging) / SQL Server / Oracle 编辑
其实,在数据中构造一些冗余的分页信息,是性能最好的方法,时间复杂度O(0)
不过不太通用

2004-09-15 10:00:00 | [匿名用户:怡红公子]
#re: 分页(Paging) / SQL Server / Oracle 编辑
指代好像比较混乱,为了便于说话,文中的 SQL Server 的两个编号分别 SS1, SS2,Oracle 的那个编号 Ora1。
大家也可以把贴出来的想法按此序编个号码,方便说话。
2004-09-15 09:39:00 | [匿名用户:破宝]
#re: 分页(Paging) / SQL Server / Oracle 编辑
我就用那种嵌套,,呵呵


,,最好的办法就是别用分页,,,就像写Blog一样。
2004-09-15 09:35:00 | [匿名用户:TommyWOo]
#re: 分页(Paging) / SQL Server / Oracle 编辑
to albertmozart:

你是说 SQL Server 的那个吗?那我没什么可说的。

我想文章里主要想说的是 SQL Server 的临时表法,以及 Oracle 的那个嵌套法,这两个都具有相当的通用性。
2004-09-15 09:18:00 | [匿名用户:破宝]
#re: 分页(Paging) / SQL Server / Oracle 编辑
我也曾经研究过这个问题,发现没有一个分页是通用的,郁闷ing...
2004-09-15 09:13:00 | [匿名用户:chikinglau]
#re: 分页(Paging) / SQL Server / Oracle 编辑
当然是嵌套那个
2004-09-15 00:31:00 | [匿名用户:albertmozart]
#re: 分页(Paging) / SQL Server / Oracle 编辑
to albertmozart :
哪一个?
2004-09-14 22:33:00 | [匿名用户:破宝]
#re: 分页(Paging) / SQL Server / Oracle 编辑
这样的做法执行效率很不好,你不妨看看SDK里关于分页部份的文章,今天刚好我也在想Oracle下怎么弄这个东东.
2004-09-14 22:30:00 | [匿名用户:albertmozart]
对不起,目前本随笔不允许发表新评论.

Powered by: Joycode.MVC引擎 0.5.1.8