日期:2014-05-18  浏览次数:20472 次

跪求一高效的SQL分页存储过程!
我在网上搜索了下面这个SQL存储过程
在一百二十万条记录中测试,
以每页10为大小,查询第10000页的记录,
结果用时15秒!
求高手给个真正高效的分页存储过程!
SQL code

-- 获取指定页的数据 
CREATE PROCEDURE pagination
@tblName varchar(255), -- 表名 
@strGetFields varchar(1000) = '*', -- 需要返回的列 
@fldName varchar(255)='', -- 排序的字段名 
@PageSize int = 10, -- 页尺寸 
@PageIndex int = 1, -- 页码 
@doCount bit = 0, -- 返回记录总数, 非 0 值则返回 
@OrderType bit = 0, -- 设置排序类型, 非 0 值则降序 
@strWhere varchar(1500) = '' -- 查询条件 (注意: 不要加 where) 
AS 
declare @strSQL varchar(5000) -- 主语句 
declare @strTmp varchar(110) -- 临时变量 
declare @strOrder varchar(400) -- 排序类型 
if @doCount != 0 
begin 
if @strWhere !='' 
set @strSQL = "select count(*) as Total from [" + @tblName + "] where "+@strWhere 
else 
set @strSQL = "select count(*) as Total from [" + @tblName + "]" 
end 
--以上代码的意思是如果@doCount传递过来的不是0,就执行总数统计。以下的所有代码都是@doCount为0的情况 
else 
begin 
if @OrderType != 0 
begin 
set @strTmp = "<(select min" 
set @strOrder = " order by [" + @fldName +"] desc" 
--如果@OrderType不是0,就执行降序,这句很重要! 
end 
else 
begin 
set @strTmp = ">(select max" 
set @strOrder = " order by [" + @fldName +"] asc" 
end 
if @PageIndex = 1 
begin 
if @strWhere != '' 
set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ " from [" + @tblName + "] where " + @strWhere + " " + @strOrder 
else 
set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ " from ["+ @tblName + "] "+ @strOrder 
--如果是第一页就执行以上代码,这样会加快执行速度 
end 
else 
begin 
--以下代码赋予了@strSQL以真正执行的SQL代码 
set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ " 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) +" "+@strGetFields+ " from [" 
+ @tblName + "] where [" + @fldName + "]" + @strTmp + "([" 
+ @fldName + "]) from (select top " + str((@PageIndex-1)*@PageSize) + " [" 
+ @fldName + "] from [" + @tblName + "] where " + @strWhere + " " 
+ @strOrder + ") as tblTmp) and " + @strWhere + " " + @strOrder 
end 
end 
exec (@strSQL)
GO



------解决方案--------------------
SQL code
1------------------------------------------------
--游标不是明智的选择,在小数据量时可以使用
create   procedure hahaha 
  @sqlstr nvarchar(4000), --查询字符串 
  @currentpage int, --第N页 
  @pagesize int --每页行数 
  as 
  set nocount on 
  declare @P1 int, --P1是游标的id 
  @rowcount int 
  exec sp_cursoropen @P1 output,@sqlstr,@scrollopt=1,@ccopt=1,@rowcount=@rowcount output 
  select ceiling(1.0*@rowcount/@pagesize) as 总页数--,@rowcount as 总行数,@currentpage as 当前页 
  set @currentpage=(@currentpage-1)*@pagesize+1 
  exec sp_cursorfetch @P1,16,@currentpage,@pagesize   
  exec sp_cursorclose @P1 
  set nocount off 
  
  测试: hahaha '任何条件的SQL语句',2,10

------解决方案--------------------
HTML code
/*--用存储过程实现的分页程序

 显示指定表、视图、查询结果的第X页
 对于表中主键或标识列的情况,直接从原表取数查询,其它情况使用临时表的方法
 如果视图或查询结果中有主键,不推荐此方法

--邹建 2003.09(引用请保留此信息)--*/

/*--调用示例
 exec p_show '地区资料'

 exec p_show '地区资料',5,3,'地区编号,地区名称,助记码','地区编号'
--*/

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[p_show]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[p_show]
GO

CREATE Proc p_show
@QueryStr nvarchar(4000), --表名、视图名、查询语句
@PageSi