sqlserver 通用存储过程分页代码(附使用ROW_NUMBER()和不使用ROW_NUMBER()两种情况性能分析)
程序员文章站
2022-06-01 16:44:58
表结构: 复制代码 代码如下: create table [dbo].[xtest]( [id] [bigint] identity(1,1) not null, [xna...
表结构:
create table [dbo].[xtest](
[id] [bigint] identity(1,1) not null,
[xname] [nvarchar](50) null,
[xdemo] [nvarchar](500) null,
constraint [pk_xtest] primary key clustered
(
[id] asc
)with (pad_index = off, statistics_norecompute = off, ignore_dup_key = off, allow_row_locks = on, allow_page_locks = on) on [primary]
) on [primary]
插入50万条数据:
declare @i int
set @i=1
while(@i<500001)
begin
insert into dbo.xtest(xname,xdemo) values(cast(@i as varchar)+'name'+cast(@i as varchar),'这是第'+cast(@i as varchar)+'的内容')
set @i=@i+1
end
另外对xname建立索引。
存储过程如下:
-- =============================================
-- author: <jiangrod>
-- create date: <2010-03-03>
-- description: <sql2000通用分页存储过程>调用方法: sp_pager2000 'xtest','*','id','order by id asc','xname like ''%222name%''',3,20,0,0
-- =============================================
alter procedure [dbo].[sp_pager2000]
@tblname varchar(255), -- 表名如:'xtest'
@strgetfields varchar(1000) = '*', -- 需要返回的列如:'xname,xdemo'
@pkname nvarchar(50)='id', -- 主键名
@strorder varchar(255)='', -- 排序的字段名如:'order by id desc'
@strwhere varchar(1500) = '', -- 查询条件(注意:不要加where)如:'xname like ''%222name%'''
@pageindex int = 1, -- 页码如:2
@pagesize int = 20, -- 每页记录数如:20
@recordcount int=0 out, -- 记录总数
@docount bit=0 -- 非0则统计,为0则不统计(统计会影响效率)
as
declare @sql nvarchar(4000)
declare @sqltemp nvarchar(1000)
set @sql=' from '+@tblname
if(@strwhere!='') set @sql=@sql+' where '+@strwhere
declare @strcount nvarchar(1000)
--总记录条数
if(@docount!=0)
begin
if(@strwhere !='')
begin
set @strcount='set @num=(select count(1) from '+ @tblname + ' where '+@strwhere+' )'
end
else
begin
set @strcount='set @num=(select count(1) from '+ @tblname + ' )'
end
execute sp_executesql @strcount ,n'@num int output',@recordcount output
end
if @strwhere !=''
begin
set @strwhere=' where '+@strwhere
end
if (@pageindex>1)
begin
set @sqltemp=@pkname+' not in (select top '+cast((@pagesize*(@pageindex-1)) as nvarchar)+' '+@pkname+' '+@sql
if(@strorder!='')set @sqltemp=@sqltemp+' '+@strorder
set @sqltemp=@sqltemp+')'
set @sql='select top '+cast(@pagesize as nvarchar)+' '+@strgetfields+' '+@sql
if(@strwhere!='')set @sql=@sql+' and '+@sqltemp
else set @sql=@sql+' where '+@sqltemp
end
else
begin
set @sql='select top '+cast(@pagesize as nvarchar)+' '+@strgetfields+' '+@sql
end
if(@strorder!='') set @sql=@sql+' '+@strorder
exec(@sql)
-- =============================================
-- author: <jiangrod>
-- create date: <2010-03-03>
-- description: <sql2005及后续版本通用分页存储过程>调用方法: sp_pager2005 'xtest','*','order by id asc','xname like ''%222name%''',2,20,0,0
-- =============================================
alter procedure [dbo].[sp_pager2005]
@tblname varchar(255), -- 表名如:'xtest'
@strgetfields varchar(1000) = '*', -- 需要返回的列如:'xname,xdemo'
@strorder varchar(255)='', -- 排序的字段名如:'order by id desc'
@strwhere varchar(1500) = '', -- 查询条件(注意:不要加where)如:'xname like ''%222name%'''
@pageindex int = 1, -- 页码如:2
@pagesize int = 20, -- 每页记录数如:20
@recordcount int output, -- 记录总数
@docount bit=0 -- 非0则统计,为0则不统计(统计会影响效率)
as
declare @strsql varchar(5000)
declare @strcount nvarchar(1000)
--总记录条数
if(@docount!=0)
begin
if(@strwhere !='')
begin
set @strcount='set @num=(select count(1) from '+ @tblname + ' where '+@strwhere+' )'
end
else
begin
set @strcount='set @num=(select count(1) from '+ @tblname + ' )'
end
execute sp_executesql @strcount ,n'@num int output',@recordcount output
end
if @strwhere !=''
begin
set @strwhere=' where '+@strwhere
end
set @strsql='select * from (select row_number() over ('+@strorder+') as rowid,'
set @strsql=@strsql+@strgetfields+' from ['+@tblname+'] '+@strwhere
set @strsql=@strsql+') as sp where rowid between '+str((@pageindex-1)*@pagesize+1)
set @strsql=@strsql+' and '+str(@pageindex*@pagesize)
exec (@strsql)
对上面两个存储过程进行了测试,测试环境:酷睿2双核2.20gh,1g内存,sql server2008
对50万条数据进行了分页查询测试
查询的条件是:xname like '%222name%'
"page1:2秒937毫秒":表示打开第一页使用的时间,其他依次类推
不使用row_number()每页都要统计:
page1:2秒937毫秒
page2:3秒140毫秒
page3:3秒453毫秒
page4:3秒609毫秒
page5:3秒843毫秒
page6:4秒156毫秒
不使用row_number()仅第一页统计:
page1:2秒937毫秒
page2:0秒343毫秒
page3:0秒593毫秒
page4:0秒812毫秒
page5:1秒46毫秒
page6:1秒281毫秒
使用row_number()每页都要统计:
page1:2秒937毫秒
page2:3秒31毫秒
page3:3秒156毫秒
page4:3秒296毫秒
page5:3秒421毫秒
page6:3秒515毫秒
使用row_number()仅第一页统计:
page1:2秒937毫秒
page2:0秒218毫秒
page3:0秒359毫秒
page4:0秒468毫秒
page5:0秒578毫秒
page6:0秒687毫秒
结论:在存储过程当中如果每次都统计记录总数将会严重影响效率,相同的查询条件记录总数必定是相同的,所以如果第一页执行之后把记录总数保存起来,点击其他页次的时候命令存储过
程不再统计记录总数将会大大提高系统性能。通过测试结果看出每次都要统计总记录数使用row_number()和不使用row_number()差别不是太大,如果仅第一次统计总记录数使用row_number()将
会比不使用row_number()的效率提高很多。
复制代码 代码如下:
create table [dbo].[xtest](
[id] [bigint] identity(1,1) not null,
[xname] [nvarchar](50) null,
[xdemo] [nvarchar](500) null,
constraint [pk_xtest] primary key clustered
(
[id] asc
)with (pad_index = off, statistics_norecompute = off, ignore_dup_key = off, allow_row_locks = on, allow_page_locks = on) on [primary]
) on [primary]
插入50万条数据:
复制代码 代码如下:
declare @i int
set @i=1
while(@i<500001)
begin
insert into dbo.xtest(xname,xdemo) values(cast(@i as varchar)+'name'+cast(@i as varchar),'这是第'+cast(@i as varchar)+'的内容')
set @i=@i+1
end
另外对xname建立索引。
存储过程如下:
复制代码 代码如下:
-- =============================================
-- author: <jiangrod>
-- create date: <2010-03-03>
-- description: <sql2000通用分页存储过程>调用方法: sp_pager2000 'xtest','*','id','order by id asc','xname like ''%222name%''',3,20,0,0
-- =============================================
alter procedure [dbo].[sp_pager2000]
@tblname varchar(255), -- 表名如:'xtest'
@strgetfields varchar(1000) = '*', -- 需要返回的列如:'xname,xdemo'
@pkname nvarchar(50)='id', -- 主键名
@strorder varchar(255)='', -- 排序的字段名如:'order by id desc'
@strwhere varchar(1500) = '', -- 查询条件(注意:不要加where)如:'xname like ''%222name%'''
@pageindex int = 1, -- 页码如:2
@pagesize int = 20, -- 每页记录数如:20
@recordcount int=0 out, -- 记录总数
@docount bit=0 -- 非0则统计,为0则不统计(统计会影响效率)
as
declare @sql nvarchar(4000)
declare @sqltemp nvarchar(1000)
set @sql=' from '+@tblname
if(@strwhere!='') set @sql=@sql+' where '+@strwhere
declare @strcount nvarchar(1000)
--总记录条数
if(@docount!=0)
begin
if(@strwhere !='')
begin
set @strcount='set @num=(select count(1) from '+ @tblname + ' where '+@strwhere+' )'
end
else
begin
set @strcount='set @num=(select count(1) from '+ @tblname + ' )'
end
execute sp_executesql @strcount ,n'@num int output',@recordcount output
end
if @strwhere !=''
begin
set @strwhere=' where '+@strwhere
end
if (@pageindex>1)
begin
set @sqltemp=@pkname+' not in (select top '+cast((@pagesize*(@pageindex-1)) as nvarchar)+' '+@pkname+' '+@sql
if(@strorder!='')set @sqltemp=@sqltemp+' '+@strorder
set @sqltemp=@sqltemp+')'
set @sql='select top '+cast(@pagesize as nvarchar)+' '+@strgetfields+' '+@sql
if(@strwhere!='')set @sql=@sql+' and '+@sqltemp
else set @sql=@sql+' where '+@sqltemp
end
else
begin
set @sql='select top '+cast(@pagesize as nvarchar)+' '+@strgetfields+' '+@sql
end
if(@strorder!='') set @sql=@sql+' '+@strorder
exec(@sql)
-- =============================================
-- author: <jiangrod>
-- create date: <2010-03-03>
-- description: <sql2005及后续版本通用分页存储过程>调用方法: sp_pager2005 'xtest','*','order by id asc','xname like ''%222name%''',2,20,0,0
-- =============================================
alter procedure [dbo].[sp_pager2005]
@tblname varchar(255), -- 表名如:'xtest'
@strgetfields varchar(1000) = '*', -- 需要返回的列如:'xname,xdemo'
@strorder varchar(255)='', -- 排序的字段名如:'order by id desc'
@strwhere varchar(1500) = '', -- 查询条件(注意:不要加where)如:'xname like ''%222name%'''
@pageindex int = 1, -- 页码如:2
@pagesize int = 20, -- 每页记录数如:20
@recordcount int output, -- 记录总数
@docount bit=0 -- 非0则统计,为0则不统计(统计会影响效率)
as
declare @strsql varchar(5000)
declare @strcount nvarchar(1000)
--总记录条数
if(@docount!=0)
begin
if(@strwhere !='')
begin
set @strcount='set @num=(select count(1) from '+ @tblname + ' where '+@strwhere+' )'
end
else
begin
set @strcount='set @num=(select count(1) from '+ @tblname + ' )'
end
execute sp_executesql @strcount ,n'@num int output',@recordcount output
end
if @strwhere !=''
begin
set @strwhere=' where '+@strwhere
end
set @strsql='select * from (select row_number() over ('+@strorder+') as rowid,'
set @strsql=@strsql+@strgetfields+' from ['+@tblname+'] '+@strwhere
set @strsql=@strsql+') as sp where rowid between '+str((@pageindex-1)*@pagesize+1)
set @strsql=@strsql+' and '+str(@pageindex*@pagesize)
exec (@strsql)
对上面两个存储过程进行了测试,测试环境:酷睿2双核2.20gh,1g内存,sql server2008
对50万条数据进行了分页查询测试
查询的条件是:xname like '%222name%'
"page1:2秒937毫秒":表示打开第一页使用的时间,其他依次类推
不使用row_number()每页都要统计:
page1:2秒937毫秒
page2:3秒140毫秒
page3:3秒453毫秒
page4:3秒609毫秒
page5:3秒843毫秒
page6:4秒156毫秒
不使用row_number()仅第一页统计:
page1:2秒937毫秒
page2:0秒343毫秒
page3:0秒593毫秒
page4:0秒812毫秒
page5:1秒46毫秒
page6:1秒281毫秒
使用row_number()每页都要统计:
page1:2秒937毫秒
page2:3秒31毫秒
page3:3秒156毫秒
page4:3秒296毫秒
page5:3秒421毫秒
page6:3秒515毫秒
使用row_number()仅第一页统计:
page1:2秒937毫秒
page2:0秒218毫秒
page3:0秒359毫秒
page4:0秒468毫秒
page5:0秒578毫秒
page6:0秒687毫秒
结论:在存储过程当中如果每次都统计记录总数将会严重影响效率,相同的查询条件记录总数必定是相同的,所以如果第一页执行之后把记录总数保存起来,点击其他页次的时候命令存储过
程不再统计记录总数将会大大提高系统性能。通过测试结果看出每次都要统计总记录数使用row_number()和不使用row_number()差别不是太大,如果仅第一次统计总记录数使用row_number()将
会比不使用row_number()的效率提高很多。