首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 数据库 > SQL Server >

急求优化分页存储过程解决方法

2013-07-01 
急!求优化分页存储过程该存储过程该如何优化,才能保证查询1000000条数据能在10秒完成。(此存储过程是个通用

急!求优化分页存储过程
该存储过程该如何优化,才能保证查询1000000条数据能在10秒完成。(此存储过程是个通用的分页存储过程)
ALTER procedure [dbo].[usp_fPage]

@tblName     nvarchar(4000),         ----要显示的表或多个表的连接
@fldName     nvarchar(4000) = '*',   ----要显示的字段列表
@pageSize    int = 10,----每页显示的记录个数
@page        int = 1,----当前页码
@pageCount    int = 1 output,----查询结果分页后的总页数
@Counts    int = 1 output,          ----查询到的记录数
@fldSort    nvarchar(4000),   ----排序字段列表或条件
@Sort        bit = 0,        ----排序方法,0为升序,1为降序(如果是多字段排列Sort指代最后一个排序字段的排列顺序(最后一个排序字段不加排序标记)--程序传参如:' SortA Asc,SortB Desc,SortC ')
@strCondition    nvarchar(4000) ,    ----查询条件,不需where
@ID        nvarchar(4000),        ----主表的主键
@Dist                 bit = 0           ----是否添加查询字段的 DISTINCT 默认0不添加/1添加
)
 
AS
 
SET NOCOUNT ON  --设置不返回计数

Declare @sqlTmp nvarchar(1000)        ----存放动态生成的SQL语句
Declare @strTmp nvarchar(1000)        ----存放取得查询结果总数的查询语句
Declare @strID     nvarchar(1000)        ----存放取得查询开头或结尾ID的查询语句
 
Declare @strSortType nvarchar(10)    ----数据排序规则A
Declare @strFSortType nvarchar(10)    ----数据排序规则B
 
Declare @SqlSelect nvarchar(50)         ----对含有DISTINCT的查询进行SQL构造
Declare @SqlCounts nvarchar(50)          ----对含有DISTINCT的总数查询进行SQL构造

--判断列是否传入
if @fldName is null or @fldName=''
begin
set @fldName='*'
end
 
if @Dist  = 0
begin
    set @SqlSelect = 'Select '
    set @SqlCounts = 'Count(*)'
end
else
begin
    set @SqlSelect = 'Select Distinct '
    set @SqlCounts = 'Count(DISTINCT '+@ID+')'
end
--排序列(如果没有传入排序列,默认按主键排序)
if @fldSort is null or @fldSort=''
begin
set @fldSort=@ID
end
--排序方式
if @Sort=0
begin
    set @strFSortType=' ASC '
    set @strSortType=' DESC '
end
else
begin
    set @strFSortType=' DESC '
    set @strSortType=' ASC '
end

--------生成查询语句--------
--此处@strTmp为取得查询结果数量的语句
if @strCondition is null or @strCondition=''     --没有设置显示条件
begin
    set @sqlTmp = @SqlSelect+ @fldName + ' FROM ' + @tblName
    set @strTmp = @SqlSelect+' @Counts='+@SqlCounts+' FROM '+@tblName
    set @strID = ' FROM ' + @tblName


end
else
begin
    set @sqlTmp = @SqlSelect+ @fldName + ' FROM ' + @tblName + ' where 1=1 ' + @strCondition
    set @strTmp = @SqlSelect+' @Counts='+@SqlCounts+' FROM '+@tblName + ' where 1=1 ' + @strCondition
    set @strID = ' FROM ' + @tblName + ' where 1=1 ' + @strCondition
end
----取得查询结果总数量-----
exec sp_executesql @strTmp,N'@Counts int out ',@Counts out
declare @tmpCounts int
if @Counts = 0
    set @tmpCounts = 1
else
    set @tmpCounts = @Counts
--取得分页总数
set @pageCount=(@tmpCounts+@pageSize-1)/@pageSize
/**//**当前页大于总页数 取最后一页**/
    if @page>@pageCount
        set @page=@pageCount
--/*-----数据分页2分处理-------*/
    declare @pageIndex int --总数/页大小
    declare @lastcount int --总数%页大小 

    set @pageIndex = @tmpCounts/@pageSize
    set @lastcount = @tmpCounts%@pageSize

    if @lastcount > 0
        set @pageIndex = @pageIndex + 1
    else
        set @lastcount = @pagesize
    --//***显示分页
    if @strCondition is null or @strCondition=''     --没有设置显示条件
    begin
        if @pageIndex<2 or @page<=@pageIndex / 2 + @pageIndex % 2   --前半部分数据处理
            begin 
                if @page=1  --首页
                    set @strTmp=@SqlSelect+' top '+ CAST(@pageSize as NVARCHAR(100))+' '+ @fldName+' FROM '+@tblName                        
                        +' order by '+ @fldSort +' '+ @strFSortType
                else
                begin                    
                    set @strTmp=@SqlSelect+' top '+ CAST(@pageSize as NVARCHAR(100))+' '+ @fldName+' FROM '+@tblName
                        +' where '+@ID+' <(select min('+ @ID +') FROM ('+ @SqlSelect+' top '+ CAST(@pageSize*(@page-1) as Varchar(20)) +' '+ @ID +' FROM '+@tblName


                        +' order by '+ @fldSort +' '+ @strFSortType+') AS TBMinID)'
                        +' order by '+ @fldSort +' '+ @strFSortType
                end    
            end
        else
            begin
            set @page = @pageIndex-@page+1 --后半部分数据处理
                if @page <= 1 --最后一页数据显示                
                    set @strTmp=@SqlSelect+' * FROM ('+@SqlSelect+' top '+ CAST(@lastcount as NVARCHAR(100))+' '+ @fldName+' FROM '+@tblName
                        +' order by '+ @fldSort +' '+ @strSortType+') AS TempTB'+' order by '+ @fldSort +' '+ @strFSortType 
                else
                    set @strTmp=@SqlSelect+' * FROM ('+@SqlSelect+' top '+ CAST(@pageSize as NVARCHAR(100))+' '+ @fldName+' FROM '+@tblName
                        +' where '+@ID+' >(select max('+ @ID +') FROM ('+ @SqlSelect+' top '+ CAST(@pageSize*(@page-2)+@lastcount as Varchar(20)) +' '+ @ID +' FROM '+@tblName
                        +' order by '+ @fldSort +' '+ @strSortType+') AS TBMaxID)'
                        +' order by '+ @fldSort +' '+ @strSortType+') AS TempTB'+' order by '+ @fldSort +' '+ @strFSortType 
            end
    end
    else --有查询条件
    begin
        if @pageIndex<2 or @page<=@pageIndex / 2 + @pageIndex % 2   --前半部分数据处理
        begin
                if @page=1--首页
                    set @strTmp=@SqlSelect+' top '+ CAST(@pageSize as NVARCHAR(100))+' '+ @fldName+' FROM '+@tblName                        


                        +' where 1=1 ' + @strCondition + ' order by '+ @fldSort +' '+ @strFSortType
                else
                begin                    
                    set @strTmp=@SqlSelect+' top '+ CAST(@pageSize as NVARCHAR(100))+' '+ @fldName+' FROM '+@tblName
                        +' where '+@ID+' <(select min('+ @ID +') FROM ('+ @SqlSelect+' top '+ CAST(@pageSize*(@page-1) as Varchar(20)) +' '+ @ID +' FROM '+@tblName
                        +' where (1=1) ' + @strCondition +' order by '+ @fldSort +' '+ @strFSortType+') AS TBMinID)'
                        +' '+ @strCondition +' order by '+ @fldSort +' '+ @strFSortType
                end            
        end
        else
        begin 
            set @page = @pageIndex-@page+1 --后半部分数据处理
            if @page <= 1 --最后一页数据显示
                    set @strTmp=@SqlSelect+' * FROM ('+@SqlSelect+' top '+ CAST(@lastcount as NVARCHAR(100))+' '+ @fldName+' FROM '+@tblName
                        +' where (1=1) '+ @strCondition +' order by '+ @fldSort +' '+ @strSortType+') AS TempTB'+' order by '+ @fldSort +' '+ @strFSortType                     
            else
                    set @strTmp=@SqlSelect+' * FROM ('+@SqlSelect+' top '+ CAST(@pageSize as NVARCHAR(100))+' '+ @fldName+' FROM '+@tblName
                        +' where '+@ID+' >(select max('+ @ID +') FROM ('+ @SqlSelect+' top '+ CAST(@pageSize*(@page-2)+@lastcount as Varchar(20)) +' '+ @ID +' FROM '+@tblName


                        +' where (1=1) '+ @strCondition +' order by '+ @fldSort +' '+ @strSortType+') AS TBMaxID)'
                        +' '+ @strCondition+' order by '+ @fldSort +' '+ @strSortType+') AS TempTB'+' order by '+ @fldSort +' '+ @strFSortType                
        end    
    end
------返回查询结果-----

exec sp_executesql @strTmp

SET NOCOUNT OFF --设置返回计数
存储 性能优化 分页
[解决办法]

引用:
引用:
如果没有选取条件,还要排序,基本是没啥希望在这点时间内执行完成了。
排序可以不要。能不能将子查询替换成别的方式?我不会

可以换,但是一般不这么做。
但是如果要对100万数据分页的话,再怎么做也基本不可能少于5秒了。

一般是,对于选取的数据集合添加一个新列,里面保存着流水编号,然后where条件中,选取编号大于等于页码*每页个数,小于(页码+1)*每页个数
[解决办法]
这个过程太长了。要求又挺多,有点......

不过,你可以加上脏读试试

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;

[解决办法]
使用top方法来分页是比较慢点,可以考虑使用SQL Server 2005版本以后的row_number()函数,
可以参考《存储过程(SQL Server 2005)》
http://www.cnblogs.com/wghao/archive/2013/01/23/2873256.html

热点排行