大数据量的分页处理

我们知道,在数据量小的时候,数据的分页处理,一般情况下都没有什么问题,但是在大的数据量的情况下,我们就会有数据压力的问题,以前把所有数据都取出来,对数据库以及数据流量的压力也是非常大的,这样会造成性能会非常差。对于大的数据量分页的方法主要有下面的三种思想,它们共同的思路是:只取出我们要分页显示的数据记录,而不是全部取出来。
下面我们来具体分析这三种方法的实现以及性能的测试情况。先说明一下数据表的建立情况。

None.gif CREATE   TABLE   [ dbo ] . [ Test ]  (
None.gif    
[ ID ]   [ int ]   IDENTITY  ( 1 1 NOT   NULL  ,
None.gif    
[ T_Name ]   [ char ]  ( 32 ) COLLATE Chinese_PRC_CI_AS  NOT   NULL  ,
None.gif    
[ Voting ]   [ int ]   NOT   NULL  
None.gif
ON   [ PRIMARY ]
None.gif
GO
None.gif
None.gif
ALTER   TABLE   [ dbo ] . [ Test ]   WITH   NOCHECK   ADD  
None.gif    
CONSTRAINT   [ PK_Test ]   PRIMARY   KEY    CLUSTERED  
None.gif    (
None.gif        
[ ID ]
None.gif    )  
ON   [ PRIMARY ]  
None.gif
GO
None.gif
None.gif
ALTER   TABLE   [ dbo ] . [ Test ]   ADD  
None.gif    
CONSTRAINT   [ DF_Test_voting ]   DEFAULT  ( 0 FOR   [ Voting ]
None.gif
GO
None.gif
None.gif
CREATE    INDEX   [ IX_Test_tName_asc ]   ON   [ dbo ] . [ Test ] ( [ T_Name ] ON   [ PRIMARY ]
None.gif
GO
None.gif
None.gif
CREATE    INDEX   [ IX_Test_voting_asc ]   ON   [ dbo ] . [ Test ] ( [ Voting ] ON   [ PRIMARY ]
None.gif
GO
None.gif
None.gif
CREATE    INDEX   [ IX_Test_voting_desc ]   ON   [ dbo ] . [ Test ] ( [ ID ] ON   [ PRIMARY ]
None.gif
GO
None.gif
None.gif
CREATE    INDEX   [ IX_Test_tName_DESC ]   ON   [ dbo ] . [ Test ] ( [ T_Name ]   DESC  )  ON   [ PRIMARY ]
None.gif
GO

我们新建了一个数据库表TEST,ID是PK并且是自增长的,CLUSTERED索引。T_Name和Voting分别建了ASC和DESC的索引。由于我们只单独对t_Name和Voting字段做分页查询,所以只建立了单独的索引,而没有建相关的组合索引了。
现在只对Voting做分页处理的一个案例。分页处理,一般情况下,我们知道要显示的哪一页Page,以及分页显示的PageSize.对于一些例外在这里我们不用考虑。

方法 INDEXROWCOUNT结合来做分页处理。

None.gifCREATE PROC  dbo.TestPage_Index
None.gif           
@pageSize  INT
,
None.gif           
@pageIndex INT

None.gif
AS
None.gif  
BEGIN
None.gif      
DECLARE
None.gif        
@PageLower INT ,
None.gif        
@PageUpper INT

None.gif      
DECLARE
None.gif        
@id INT
None.gif      
DECLARE
None.gif        
@voting    INT ,
None.gif        
@maxvoting INT

None.gif                   
None.gif      
SET @PageLower = (@pageIndex - 1* @PageSize
None.gif                                          
None.gif      
SET @PageUpper = @PageLower + @PageSize
None.gif                                    
None.gif      
SET RowCount  @PageLower
None.gif      
None.gif      
SELECT   @id =  Id,
None.gif               
@voting =
 voTing
None.gif      
FROM
     Test.dbo.Test (NoLock )
None.gif      
ORDER BY voTing ASC

None.gif               
None.gif      
SET RowCount  @PageUpper
None.gif      
SELECT   @maxvoting =  voTing
None.gif      
FROM
     Test.dbo.Test (NoLock )
None.gif      
ORDER BY
 voTing
None.gif               
None.gif      
SET RowCount  @PageSize

None.gif      
None.gif      
SELECT    Id,
None.gif               t_Name,
None.gif               voTing
None.gif      
FROM
     Test.dbo.Test (NoLock )
None.gif      
WHERE    (voTing = @voting

None.gif                
AND Id > @id )
None.gif                
OR (voTing > @voting

None.gif                    
AND voTing <= @maxVoting )
None.gif      
ORDER BY
 voTing
None.gif               
None.gif      
SET RowCount  0

None.gif      
None.gif  
END
None.gif
None.gif
GO
None.gif

第二种方法:用临时表的方法来分页处理

None.gifCREATE PROC  dbo.TestPage_Tab
None.gif           
@pageSize  INT
,
None.gif           
@pageIndex INT

None.gif
AS
None.gif  
BEGIN
None.gif      
DECLARE
None.gif        
@PageLower INT ,
None.gif        
@PageUpper INT

None.gif      
DECLARE
None.gif        
@id INT
None.gif      
DECLARE
None.gif        
@voting    INT ,
None.gif        
@maxvoting INT

None.gif                   
None.gif      
CREATE TABLE  ##IndexTable (
None.gif        Id  
INT IDENTITY1  , 1
  ),
None.gif        nId 
INT
)
None.gif      
None.gif      
SET @PageLower = (@pageIndex - 1* @PageSize

None.gif                                          
None.gif      
SET @PageUpper = @PageLower + @PageSize
None.gif      
SET RowCount  @PageUpper
None.gif      
INSERT INTO  ##IndexTable
None.gif                 (nId)
None.gif      
SELECT
   Id
None.gif      
FROM
     Test.dbo.Test (NoLock )
None.gif      
ORDER BY
 voTing
None.gif      
SET RowCount  @PageSize

None.gif      
SELECT   a.*
None.gif      
FROM      Test.dbo.Test a (NoLock),
None.gif               ##IndexTable t (NoLock)
None.gif      
WHERE    a.Id =
 t.nId
None.gif               
AND t.Id > @PageLower

None.gif               
AND t.Id <= @PageUpper
None.gif      
ORDER BY  t.Id
None.gif      
SET RowCount  0

None.gif      
DROP TABLE  ##IndexTable 
None.gif      
None.gif  
END

None.gif
None.gif
GO

第三种方法:用Cursor 来做分页处理

None.gifCREATE PROC  dbo.TestPage_CurSor
None.gif           
@pageSize  INT
,
None.gif           
@pageIndex INT

None.gif
AS
None.gif  
BEGIN
None.gif      
DECLARE
None.gif        
@PageLower INT ,
None.gif        
@PageUpper INT

None.gif      
DECLARE
None.gif        
@id INT ,
None.gif        
@i  INT

None.gif      
DECLARE
None.gif        
@voting    INT ,
None.gif        
@maxvoting INT

None.gif      
DECLARE
None.gif        
@condition CHAR(400 )
None.gif      
DECLARE

None.gif        
@cur  AS  CURSOR
None.gif      
SET @PageLower = (@pageIndex - 1* @PageSize
None.gif      
SET @PageUpper = @PageLower + @PageSize
None.gif      
SET RowCount  @PageUpper
None.gif      
SET @cur = CURSOR FAST_FORWARD READ_ONLY FOR SELECT    Id
None.gif                                                   
FROM
     Test.dbo.Test (NoLock )
None.gif                                                   
ORDER BY
 voTing
None.gif      
OPEN @cur

None.gif      
SET RowCount  0
None.gif      
FETCH NEXT FROM @cur
None.gif      
INTO @id
None.gif      
SET @i = 1
None.gif      
WHILE @@FETCH_STATUS = 0
None.gif          
BEGIN
None.gif          
None.gif              
IF (@i >= @PageLower + 1 )
None.gif                 
AND @i <= @pageUpper

None.gif                  
BEGIN
None.gif                      
IF @i = @PageLower + 1
None.gif                          
BEGIN
None.gif                              
SET @condition = Rtrim(CAST(@id AS CHAR(10 )))
None.gif                          
END

None.gif                       
ELSE
None.gif                        
BEGIN
None.gif                            
SET @condition = Rtrim(@condition+ ',' + Rtrim(CAST(@id AS CHAR(10 )))
None.gif                        
END

None.gif                  
END
None.gif              
SET @i = @i + 1
None.gif              
FETCH NEXT FROM @cur
None.gif              
INTO @id
None.gif          
END
None.gif      
CLOSE @cur
None.gif      
DEALLOCATE @cur
None.gif      
IF @condition IS NOT NULL  
None.gif          
EXEC'select * from test..test(nolock) where id in (' + @Condition + ')'
)
None.gif  
END

None.gif
GO


测试比较
我现在的机器是T43 ,CPU 1.86G SQL SERVER 2000
TEST表里有400,000条记录
测试程序如下:

None.gif DECLARE    @dt   DATETIME
None.gif
None.gif
SET   @dt   =   Getdate ()
None.gif
None.gif
EXEC  TestPage_CurSor   25 , 200
None.gif
None.gif
SELECT   Getdate ()  -   @dt   AS  m_CurSor
None.gif
None.gif
SET   @dt   =   Getdate ()
None.gif
None.gif
EXEC  TestPage_Index   25 , 200
None.gif
None.gif
SELECT   Getdate ()  -   @dt   AS  m_Index
None.gif
None.gif
SET   @dt   =   Getdate ()
None.gif
None.gif
EXEC  TestPage_Tab   25 , 200
None.gif
None.gif
SELECT   Getdate ()  -   @dt   AS  m_Tab

测试的结果为:
 


我们可以看到测试的结果是如此的悬殊:
第一种对比下来,基本上没有花时间,就处理了
第二种花了50ms的时间,但是多了一个临时表
第三种花了近6s的时间才能处理。
在数据量小的时候,三种方法都差不多,但是在大的数据量的情况却是如此之大,所以如果有开发人员遇到相同的问题的时候,可以参考这个例子。
对于用临时表的做法,如果查询的视图,没有主键的时候,请用临时表,第一种处理完全依赖于索引,速度才如此快。

转载于:https://www.cnblogs.com/dicman/archive/2006/07/14/450539.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值