你的位置:首页 > 数据库

[数据库]分页存储过程效率对比


1. 随便找了个网上效率被认为比较高的分页过程

    if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[xp_getpager_user_dt]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)  
    drop procedure [dbo].[xp_getpager_user_dt]  
    GO  
    CREATE PROCEDURE [dbo].[xp_getpager_user_dt]  
    @pcount int output,    --总页数输出  
    @rcount int output,    --总记录数输出  
    @tablename nvarchar(100),    --查询表名  
    @keys varchar(50),        --主键  
    @fields nvarchar(500),    --查询字段  
    @where nvarchar(3000),    --查询条件  
    @sortfields nvarchar(100),    --排序字段  
    @beginindex int=0,        --开始位置  
    @pageindex int=1,        --当前页数  
    @pagesize int=100        --页大小  
    AS  
    SET NOCOUNT ON  
    SET ANSI_WARNINGS ON  
    IF @pagesize < 0 OR @pageindex < 0  
    BEGIN          
    RETURN  
    END  
    DECLARE @new_where1 NVARCHAR(3000)  
    DECLARE @new_order1 NVARCHAR(100)  
    DECLARE @new_order2 NVARCHAR(100)  
    DECLARE @Sql NVARCHAR(4000)  
    DECLARE @SqlCount NVARCHAR(4000)  
    DECLARE @Top int  
    if(@beginindex <=0)  
        set @beginindex=0  
    else  
        set @beginindex=@beginindex-1  
    IF ISNULL(@where,'') = ''  
        SET @new_where1 = ' '  
    ELSE  
        SET @new_where1 = ' WHERE ' + @where  
    IF ISNULL(@sortfields,'') <> ''   
    BEGIN  
        SET @new_order1 = ' ORDER BY ' + Replace(@sortfields,'desc','')  
        SET @new_order1 = Replace(@new_order1,'asc','desc')  
        SET @new_order2 = ' ORDER BY ' + @sortfields  
    END  
    ELSE  
    BEGIN  
        SET @new_order1 = ' ORDER BY ID DESC'  
        SET @new_order2 = ' ORDER BY ID ASC'  
    END  
    SET @SqlCount = 'SELECT @rcount=COUNT(1),@pcount=CEILING((COUNT(1)+0.0)/'  
                + CAST(@pagesize AS NVARCHAR)+') FROM ' + @tablename + @new_where1  
    EXEC SP_EXECUTESQL @SqlCount,N'@rcount INT OUTPUT,@pcount INT OUTPUT',  
                   @rcount OUTPUT,@pcount OUTPUT  
    IF @pageindex > CEILING((@rcount+0.0)/@pagesize)    --如果输入的当前页数大于实际总页数,则把实际总页数赋值给当前页数  
    BEGIN  
        SET @pageindex =  CEILING((@rcount+0.0)/@pagesize)  
    END  
    set @sql = 'select '+ @fields +' from ' + @tablename + ' w1 '  
        + ' where '+ @keys +' in ('  
            +'select top '+ ltrim(str(@pagesize)) +' ' + @keys + ' from '  
            +'('  
                +'select top ' + ltrim(STR(@pagesize * @pageindex + @beginindex)) + ' ' + @keys + ' FROM '  
            + @tablename + @new_where1 + @new_order2   
            +') w ' + @new_order1  
        +') ' + @new_order2  
    print(@sql)  
    Exec(@sql)  
    GO 

 

2. 优化后的分页过程

create PROC [dbo].[xp_GetPager_user_dt2]    
@quitdate nvarchar(10)='2015-01-01',
@userno nvarchar(10)='',
@sortfields nvarchar(100)='',
@pageindex int=1,
@pagesize int=5
AS
begin  

--构建执行脚本
declare @sql nvarchar(1800)='',
        --存储对象
        @tablename NVARCHAR(50)=' v_pn_users_fromlocal',
        --返回字段
        @returnfields nvarchar(1000)='',
        --where 条件
        @where nvarchar(200)=' where 1=1 ',--and abs([Status]) >= 10 and [Status] <> 40  and isvalid<>-1 ,
        --上次查询数量
        @lastcount int =-1  

        --计算前面查询的数据总数
        set @lastcount=(@pageindex-1)*@pagesize
        if @lastcount<0 set @lastcount=0
        --判断排序字段
        if @sortfields=''
          set @sortfields='quitdate'
          
 
--*******************************************返回字段设定*****************************************
set @returnfields='code,name,fname,email,isvalid,hiredate,hirevalid,quitdate,costcenter,sex,IDCard,PassDate '
--*******************************************由条件构建Where***************************************
 
if @quitdate<>'2015-01-01'
   set @where+=' and quitdate  > '''+@quitdate+''''
if @userno<>''
   set @where+=' and code = '''+@userno+''''  
 
--*******************************************由条件构建SQL***************************************
set @sql='

declare @lastmaxid int=0,@total int
--缓存的临时表,并创建检索rowID
if object_id(''tempdb..#t'') is not null
    drop table #t

select row_number() over (order by '+@sortfields+') rowid, * into #t from '+@tablename

set @sql += @where

--获取按照执行排序,前面查询的数据的最大ID
set @sql +=' select top '+cast(@lastcount as nvarchar)+'  @lastmaxid=max(rowid) from #t'
set @sql+= ' group by rowid'

--获取符合条件的数据总数
set @sql+=' select @total=count(*) from #t'

--**********************************************构造执行返回结果的SQL*****************************************
set @sql+=' select '
if @pagesize>0
   set @sql+='top '+cast(@pagesize as nvarchar)
   set @sql+=' rowid '
   
   if @returnfields<>''
   begin
        set @sql+=','+@returnfields        
   end            
   set @sql+=' from #t
            where rowid>@lastmaxid order by rowid'

set @sql+=' select @total total,'+cast(@pagesize as nvarchar)+' pagesize,'+cast(@pageindex as nvarchar)+' pageindex'

set @sql+=' if object_id(''tempdb..#t'') is not null
    drop table #t'
exec(@sql)  

END

 

 

效率对比

1. declare @pcount int,@rcount int
exec [dbo].[xp_getpager_user_dt]  
    @pcount  output,    --总页数输出  
    @rcount  output,    --总记录数输出  
    @tablename ='v_pn_users_fromlocal',    --查询表名  
    @keys ='code',        --主键  
    @fields ='code,name,fname,email,isvalid,hiredate,hirevalid,quitdate,costcenter,sex,IDCard,PassDate',    --查询字段  
    @where ='quitdate>''2015-01-01''',    --查询条件  
    @sortfields ='quitdate',    --排序字段  
    @beginindex =0,        --开始位置  
    @pageindex =1,        --当前页数  
    @pagesize =100

执行时间:1 min 18s

2. [xp_GetPager_user_dt2] @quitdate='2015-01-01',@pagesize=100

执行时间:<1s