请教一个数据库问题:如何分页显示记录

runrunrun 2003-04-19 04:37:51
有这样一个表格,里面有大约100万条记录。用一个查询语句查出所有的记录(当然不可能全部返回了),想做成分页显示,比如每页有100条,那么第一页只显示序号为1到100的记录。依次类推。
本来只显示100条记录应该是很快的,但是实际运行速度却很慢,我估计是把所有的记录全给返回了,然后再挑出100条来显示。不知道有什么方法可以获取从给定的位置开始给定数目的记录,并且系统开销很小。

不要告诉我用主键ID, 因为排序不一定是按照主键来的。实际上除了主键也没有其他的索引(因为重复率很高)。
...全文
74 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
netgui 2003-04-22
  • 打赏
  • 举报
回复
学习中
runrunrun 2003-04-21
  • 打赏
  • 举报
回复
谢谢 happydreamer(黑DD) 及各位的回答,我试了一下,你们是对的。

本来最好是数据库直接支持,即然可以有 select top N ..., 为什么不可以有类似
select between N1 and N2 ...的语句呢?
数据库直接支持的效率显示是最高的
wgy2008 2003-04-19
  • 打赏
  • 举报
回复
修改
create procedure cur_num @num int,@num1
as
declare @sql varchar(8000)
set @sql = 'select top '+ cast(@num as varchar(100)) + ' * from 表 where id >@num1'
exec(@sql)
wgy2008 2003-04-19
  • 打赏
  • 举报
回复
create procedure cur_num @num int
as
declare @sql varchar(8000)
set @sql = 'select top '+ cast(@num as varchar(100)) + ' * from 表'
exec(@sql)
happydreamer 2003-04-19
  • 打赏
  • 举报
回复
一般的方法
select Top pageSize *
from T
where SortField NOT IN (select Top pageSize*pagei SortField
from T
order by SortField )
order by SortField

例如,每页7条,列印第7页:
select Top 10 *
from T
where SortField NOT IN (select Top 70 SortField
from T
order by SortField )
order by SortField


or

CREATE PROCEDURE Get_Customers_By_Page
@CurrentPage int,
@PageSize int,
@TotalRecords int output
as

SELECT identity(int,1,1) as id ,* into #TempTable from table

DECLARE @FirstRec int, @LastRec int
SELECT @FirstRec = (@CurrentPage - 1) * @PageSize
SELECT @LastRec = (@CurrentPage * @PageSize + 1)

SELECT
*
FROM
#TempTable
WHERE
ID > @FirstRec
AND
ID < @LastRec

SELECT @TotalRecords = COUNT(*) FROM table
runrunrun 2003-04-19
  • 打赏
  • 举报
回复
谢谢w_rose,你说得对。我回去试一试,星期一再结帐
saucer 2003-04-19
  • 打赏
  • 举报
回复
>>>>但是实际运行速度却很慢

把你的SQL语句贴出来, 或这么做

如果你排序的话,第一次用
select top 100 * from yourtable order by SomeField

记住每页的第一个和最后一个记录

往后翻页,你用
select top 100 * from yourtable where SomeField > '最后一个记录' order by
SomeField

往前翻页,你用
select * from (select top 100 * from yourtable where SomeField < '第一个
记录' order by SomeField desc ) t order by SomeField


>>>>不要告诉我用主键ID, 因为排序不一定是按照主键来的。实际上除了主键也没有其他的>>>>索引

速度慢冤不得人, 祝你好运!
doudouniwan 2003-04-19
  • 打赏
  • 举报
回复
SQLServer中分页这样比较好:

exec('SELECT Top '+cast(@每页大小 as varchar)+' * FROM T WHERE SortField NOT IN (SELECT TOP '+cast(@每页大小*@第几页 as varchar)+' SortField from T )')

速度不是很快,但是没有什么问题
pengdali 2003-04-19
  • 打赏
  • 举报
回复
楼上说的对!

exec('SELECT Top '+cast(@每页大小 as varchar)+' * FROM T WHERE SortField NOT IN (SELECT TOP '+cast(@每页大小*@第几页 as varchar)+' SortField from T )')

肯定比你ado.net里做的快!
w_rose 2003-04-19
  • 打赏
  • 举报
回复
这里,之所以慢,不在于服务器上查询中间结果需要的数据的多,而在于要将过多的结果数据在网络上传送到客户端。
w_rose 2003-04-19
  • 打赏
  • 举报
回复
傻了吧叽的ado.net是怎么做的呢?他把100万数据读到客户端,然后只留下需要的一页数据,剩下的再丢弃。

所以,即使你认为“很慢”的查询语句,也比你用ado.net的所谓分页功能要快不知道多少倍。
w_rose 2003-04-19
  • 打赏
  • 举报
回复
那些都是“直接在数据库了实现”的方法啊!!!!

只有“ado.net 里的 DbDataAdapter.Fill ”才是在客户端实现的方法。
runrunrun 2003-04-19
  • 打赏
  • 举报
回复
唉,看来是没有很好的解决方法了。
以上的解决方法无非有以下几种:
1. 用 select top 100 * from T where .. not in ( select top beginIndex ... ), 但是当 beginIndex 很大的时候,比如 1000000, 这样做无疑效率很低。

2. 利用索引,把每次查询后的索引值记录。但是当索引值重复很大或者根本没有索引时,这种方法就不行了。

3. 用类似 oracle里的rowid, 但是 sql-server 里没有。 :-(

我现在用的是 ado.net 里的 DbDataAdapter.Fill 方法里的功能来实现分页的,但是效率很低,所以想找一种能直接在数据库里实现的方法。

各位大侠帮忙啊
w_rose 2003-04-19
  • 打赏
  • 举报
回复
不外乎,利用触发器,在记录变更时重新计算变更记录以后的行号。
pengdali 2003-04-19
  • 打赏
  • 举报
回复
SQLServer中分页只能这样了:

exec('SELECT Top '+cast(@每页大小 as varchar)+' * FROM T WHERE SortField NOT IN (SELECT TOP '+cast(@每页大小*@第几页 as varchar)+' SortField from T )')

只有oracle里有rowid速度也很快,期待sqlserver下一个版本有rowid
runrunrun 2003-04-19
  • 打赏
  • 举报
回复
to: happydreamer(黑DD)
你说的意思我明白,我也这样想过,但它的效率直在值得商榷,
比如说我想取得第 500001到500100 的100条记录,那么你的语句就是:
select Top 10 * from T
where SortField NOT IN (select Top 500000 SortField
from T order by SortField )order by SortField
效率很低吧。你的另一种方法也一样,先把这么多记录倒到另一个临时表中,也一定很慢。


to: saucer(思归, MS .NET MVP) :
你说的第一页用 select top 100 * ... 我能理解。但是以后的记录你用下面的语句:
select top 100 * from yourtable where SomeField > '最后一个记录' order by
SomeField
就有一个假设:SomeField 必须是唯一索引。 如果根本就没有索引的话,该怎么办呢。
我想要的其实就是类似 select between 500001 and 500100 * from T 的这样一个语句。但又要顾及到效率。


to wgy2008(北极光) :
你说的也只是显示头一百条时的情况。

22,209

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server 疑难问题
社区管理员
  • 疑难问题社区
  • 尘觉
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧