[百万级]通用分页存储过程.[千万级]实现千万级数据的分页显示!(转)

有关分页 SQL 的资料很多,有的使用存储过程,有的使用游标。本人不喜欢使用游标,我觉得它耗资、效率低;使用存储过程是个不错的选择,因为存储过程是经过预编译的,执行效率高,也更灵活。先看看单条 SQL 语句的分页 SQL 吧。

方法1:
适用于 SQL Server 2000/2005
SELECT TOP 页大小 *
FROM table1
WHERE id NOT IN
          (
          
SELECT TOP 页大小*(-1) id FROM table1 ORDER BY id
          )
ORDER BY id

方法2:
适用于 SQL Server 2000/2005
SELECT TOP 页大小 *
FROM table1
WHERE id >
          (
          
SELECT ISNULL(MAX(id),0
          FROM 
                (
               
SELECT TOP 页大小*(-1) id FROM table1 ORDER BY id
                ) 
A
          )
ORDER BY id

方法3:
适用于 SQL Server 2005

SELECT TOP 页大小 * 
FROM 
        (
        
SELECT ROW_NUMBER() OVER (ORDER BY id) AS RowNumber,* FROM table1
        ) A
WHERE RowNumber > 页大小*(页数-1)


说明,页大小:每页的行数;页数:第几页。使用时,请把“页大小”和“页大小*(页数-1)”替换成数字。

 

 

 

其它的方案:如果没有主键,可以用临时表,也可以用方案三做,但是效率会低。
建议优化的时候,加上主键和索引,查询效率会提高。

通过SQL 查询分析器,显示比较:我的结论是:
分页方案二:(利用ID大于多少和SELECT TOP分页)效率最高,需要拼接SQL语句
分页方案一:(利用Not In和SELECT TOP分页)   效率次之,需要拼接SQL语句
分页方案三:(利用SQL的游标存储过程分页)    效率最差,但是最为通用





/*

名称:spAll_ReturnRows
输入:
输出:
调用:
EXEC spAll_ReturnRows 'select * FROM 表名', 页号, 返回记录数, '主键', '排序字段'
spAll_ReturnRows 'select * FROM all_Categories',2,10,'[ID]','[ID]'
说明:[百万级]通用存储过程.分页存储过程..返回指定返回条数、指定页数的记录
作者:Dili J.F. Senders
邮件:diliatwellknow.net
更新:20040610
版权:转述时请注明来源:用思维创造未来的Wellknow.net
*/


create PROCEDURE dbo.spAll_ReturnRows
(
@SQL nVARCHAR(4000),
@Page int,
@RecsPerPage int,
@ID VARCHAR(255),
@Sort VARCHAR(255)
)
AS

DECLARE @Str nVARCHAR(4000)

SET @Str='select TOP '+cast(@RecsPerPage AS VARCHAR(20))+' * FROM ('+@SQL+') T where T.'+@ID+' NOT IN 
(select TOP 
'+cast((@RecsPerPage*(@Page-1)) AS VARCHAR(20))+' '+@ID+' FROM ('+@SQL+') T9 ORDER BY '+@Sort+') ORDER BY '+@Sort

PRINT @Str

EXEC sp_ExecuteSql @Str
GO




/*
名称:spAll_deleteNoneUnique
输入:要查询的表名和字段列表
输出:
调用:
说明:实现千万级数据的分页显示!--可以在5秒内获取1448万条记录里的第1200页的100条记录,雄不?
作者:铁拳版权:转述时请注明来源:用思维创造未来的Wellknow.net
*/

create PROCEDURE GetRecordFromPage
@tblName varchar(255), -- 表名
@fldName varchar(255), -- 字段名
@PageSize int = 10-- 页尺寸
@PageIndex int = 1-- 页码
@IsCount bit = 0-- 返回记录总数, 非 0 值则返回
@OrderType bit = 0-- 设置排序类型, 非 0 值则降序
@strwhere varchar(1000= '' -- 查询条件 (注意: 不要加 where)
AS

declare @strSQL varchar(6000-- 主语句
declare @strTmp varchar(100-- 临时变量
declare @strOrder varchar(400-- 排序类型

if @OrderType != 0
begin
set @strTmp = "<(select min"
set @strOrder = " order by [" + @fldName +"] desc"
end
else
begin
set @strTmp = ">(select max"
set @strOrder = " order by [" + @fldName +"] asc"
end

set @strSQL = "select top " + str(@PageSize+ " * from ["
+ @tblName + "
] where [" + @fldName + "]+ @strTmp + "(["
+ @fldName + "
]from (select top " + str((@PageIndex-1)*@PageSize+ " ["
+ @fldName + "
] from [" + @tblName + "]+ @strOrder + ") as tblTmp)"
+ @strOrder

if @strwhere != ''
set @strSQL = "select top " + str(@PageSize+ " * from ["
+ @tblName + "
] where [" + @fldName + "]+ @strTmp + "(["
+ @fldName + "
]from (select top " + str((@PageIndex-1)*@PageSize+ " ["
+ @fldName + "
] from [" + @tblName + "] where " + @strwhere + " "
+ @strOrder + ") as tblTmp) and " + @strwhere + " " + @strOrder

if @PageIndex = 1
begin
set @strTmp = ""
if @strwhere != ''
set @strTmp = " where " + @strwhere

set @strSQL = "select top " + str(@PageSize+ " * from ["
+ @tblName + "
]+ @strTmp + " " + @strOrder
end

if @IsCount != 0
set @strSQL = "select count(*as Total from [" + @tblName + "]"

exec (@strSQL)

GO

个人研究百万级数据提出问题总结如下: 
1.除了提高硬件方面 
2.采取折中方法,一次提出几百万数据也没有什么实在意义 

不过存储过程写的还是很精妙。 

p
=pagesize,n为返回页数,SQL="select * from product where id<200000

1.(select * from product where id<200000as t 
2.(select top p*(n-1) t.id from t order by id ascas t1 
3.select top p * from t where id not in t1 order by id asc 

SQL: 
select top p * from (select * from product where id<200000) t where t.id not in (select top p*(n-1) id from t order by id ascorder by id asc 
[注:子查询里面别名t 其实并不存在,应该用1.重新代替] 

SQL存储过程: 
SET @str='select top'+cast(@p as varchar(20))+' * from ('+@SQL+') t where t.'+@ID+' not in (select top '+cast((@p*(@n-1)) as varchar(20))+' '+@ID+' from ('+SQL+') order by '+@Sort+') order by '+@Sort 

PRINT @str 

/*
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/wind8303/archive/2009/02/21/3917862.aspx
*/

百万级数据测试结果如下:
//////////////////////////////
///result:100W数据
///
///条件:VirtualItemCount=200000
///->转1页 33.924982085712 milliseconds,33.3696042374101 milliseconds,31.1483722093171 milliseconds
///->转1000页 247.380882207096 milliseconds,190.643224208663 milliseconds,240.085262233049 milliseconds
///->转10000页 2393.90201827327 milliseconds,1903.65535284512 milliseconds,1839.06278591273 milliseconds
///
///条件:VirtualItemCount=all
///->1 10.2540965402027 milliseconds,7.47608983823363 milliseconds,15.5991892824367 milliseconds
///->1000 273.380555349912 milliseconds,190.414982909839 milliseconds,217.308345055028 milliseconds
///->10000 1845.92064075183 milliseconds,1951.84974626663 milliseconds,1904.51831168487 milliseconds
///
///2s处理百万数据
//////////////////////////////

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/wind8303/archive/2009/02/21/3917862.aspx

posted @ 2009-09-19 09:58  ForFreeDom  阅读(581)  评论(0编辑  收藏  举报