sql分页查询几种写法
关于sql语句分页,网上也有很多,我贴一部分过来,并且总结自己已知的分页到下面,方便日后查阅
1.创建测试环境,(插入100万条数据大概耗时5分钟)。
create database dbtest use dbtest --创建测试表 create table pagetest ( id int identity(1,1) not null, col01 int null, col02 nvarchar(50) null, col03 datetime null ) --1万记录集 declare @i int set @i=0 while(@i<10000) begin insert into pagetest select cast(floor(rand()*10000) as int),left(newid(),10),getdate() set @i=@i+1 end
2.几种典型的分页sql,下面例子是每页50条,198*50=9900,取第199页数据。
--写法1,not in/top
select top 50 * from pagetest where id not in (select top 9900 id from pagetest order by id) order by id
--写法2,not exists
select top 50 * from pagetest where not exists (select 1 from (select top 9900 id from pagetest order by id)a where a.id=pagetest.id) order by id
--写法3,max/top
select top 50 * from pagetest where id>(select max(id) from (select top 9900 id from pagetest order by id)a) order by id
--写法4,row_number()
select top 50 * from (select row_number()over(order by id)rownumber,* from pagetest)a where rownumber>9900 select * from (select row_number()over(order by id)rownumber,* from pagetest)a where rownumber>9900 and rownumber<9951 select * from (select row_number()over(order by id)rownumber,* from pagetest)a where rownumber between 9901 and 9950
--写法5,在csdn上一帖子看到的,row_number() 变体,不基于已有字段产生记录序号,先按条件筛选以及排好序,再在结果集上给一常量列用于产生记录序号
select * from ( select row_number()over(order by tempcolumn)rownumber,* from (select top 9950 tempcolumn=0,* from pagetest where 1=1 order by id)a )b where rownumber>9900
3.分别在1万,10万(取1990页),100(取19900页)记录集下测试。
测试sql:
declare @begin_date datetime declare @end_date datetime select @begin_date = getdate() <.....your code.....> select @end_date = getdate() select datediff(ms,@begin_date,@end_date) as '毫秒'
1万:基本感觉不到差异。
10万:
4.结论:
1.max/top,row_number()都是比较不错的分页方法。相比row_number()只支持sql2005及以上版本,max/top有更好的可移植性,能同时适用于sql2000,access。
2.not exists感觉是要比not in效率高一点点。
3.row_number()的3种不同写法效率看起来差不多。
4.row_number() 的变体基于我这个测试效率实在不好。原帖在这里
ps.上面的分页排序都是基于自增字段id。测试环境还提供了int,nvarchar,datetime类型字段,也可以试试。不过对于非主键没索引的大数据量排序效率应该是很不理想的。
5.简单将rownumber,max/top的方式封装到存储过程。
rownumber(): alter procedure [dbo].[proc_sqlpagebyrownumber] ( @tbname varchar(255), --表名 @tbgetfields varchar(1000)= '*',--返回字段 @orderfldname varchar(255), --排序的字段名 @pagesize int=20, --页尺寸 @pageindex int=1, --页码 @ordertype bit = 0, --0升序,非0降序 @strwhere varchar(1000)='', --查询条件 --@totalcount int output --返回总记录数 ) as -- ============================================= -- author: allen (liyuxin) -- create date: 2012-03-30 -- description: 分页存储过程(支持多表连接查询) -- modify [1]: 2012-03-30 -- ============================================= begin declare @strsql varchar(5000) --主语句 declare @strsqlcount nvarchar(500)--查询记录总数主语句 declare @strorder varchar(300) -- 排序类型 --------------总记录数--------------- if isnull(@strwhere,'') <>'' set @strsqlcount='select @totalcout=count(*) from ' + @tbname + ' where 1=1 '+ @strwhere else set @strsqlcount='select @totalcout=count(*) from ' + @tbname --exec sp_executesql @strsqlcount,n'@totalcout int output',@totalcount output --------------分页------------ if @pageindex <= 0 set @pageindex = 1 if(@ordertype<>0) set @strorder=' order by '+@orderfldname+' desc ' else set @strorder=' order by '+@orderfldname+' asc ' set @strsql='select * from (select row_number() over('+@strorder+') rowno,'+ @tbgetfields+' from ' + @tbname + ' where 1=1 ' + @strwhere+' ) tb where tb.rowno between '+str((@pageindex-1)*@pagesize+1)+' and ' +str(@pageindex*@pagesize) exec(@strsql) select @totalcount end
public static sqlparameter makeinparam(string paramname, sqldbtype dbtype, int32 size, object value) { return makeparam(paramname, dbtype,size, parameterdirection.input, value); } public static sqlparameter makeoutparam(string paramname, sqldbtype dbtype) { return makeparam(paramname, dbtype, 0, parameterdirection.output, null); } public static sqlparameter makeparam(string paramname, sqldbtype dbtype, int32 size, parameterdirection direction, object value) { sqlparameter param; if (size > 0) param = new sqlparameter(paramname, dbtype, size); else param = new sqlparameter(paramname, dbtype); param.direction = direction; if (!(direction == parameterdirection.output && value == null)) param.value = value; return param; } /// <summary> /// 分页获取数据列表及总行数 /// </summary> /// <param name="tbname">表名</param> /// <param name="tbgetfields">返回字段</param> /// <param name="orderfldname">排序的字段名</param> /// <param name="pagesize">页尺寸</param> /// <param name="pageindex">页码</param> /// <param name="ordertype">false升序,true降序</param> /// <param name="strwhere">查询条件</param> public static dataset getpagelist(string tbname, string tbgetfields, string orderfldname, int pagesize, int pageindex, string strwhere) { sqlparameter[] parameters = { makeinparam("@tbname",sqldbtype.varchar,255,tbname), makeinparam("@tbgetfields",sqldbtype.varchar,1000,tbgetfields), makeinparam("@orderfldname",sqldbtype.varchar,255,orderfldname), makeinparam("@pagesize",sqldbtype.int,0,pagesize), makeinparam("@pageindex",sqldbtype.int,0,pageindex), makeinparam("@ordertype",sqldbtype.bit,0,ordertype), makeinparam("@strwhere",sqldbtype.varchar,1000,strwhere), // makeoutparam("@totalcount",sqldbtype.int) }; return runprocedure("proc_sqlpagebyrownumber", parameters, "ds"); }
调用:
public datatable getlist(string tbname, string tbgetfields, string orderfldname, int pagesize, int pageindex, string strwhere, ref int totalcount) { dataset ds = dal.getlist(tbname, tbgetfields, orderfldname, pagesize, pageindex, strwhere); totalcount = convert.toint32(ds.tables[1].rows[0][0]); return ds.tables[0]; }
注意:多表连接时需注意的地方
1.必填项:tbname,orderfldname,tbgetfields
2.实例:
tbname =“userinfo u inner join department d on u.depid=d.id” tbgetfields=“u.id as userid,u.name,u.sex,d.id as depid,d.defname” orderfldname=“u.id,asc|u.name,desc” (格式:name,asc|id,desc) strwhere:每个条件前必须添加 and (例如:and userinfo.depid=1 )
max/top:(简单写了下,需要满足主键字段名称就是"id")
create proc [dbo].[spsqlpagebymaxtop] @tbname varchar(255), --表名 @tbfields varchar(1000), --返回字段 @pagesize int, --页尺寸 @pageindex int, --页码 @strwhere varchar(1000), --查询条件 @strorder varchar(255), --排序条件 @total int output --返回总记录数 as declare @strsql varchar(5000) --主语句 declare @strsqlcount nvarchar(500)--查询记录总数主语句 --------------总记录数--------------- if @strwhere !='' begin set @strsqlcount='select @totalcout=count(*) from ' + @tbname + ' where '+ @strwhere end else begin set @strsqlcount='select @totalcout=count(*) from ' + @tbname end --------------分页------------ if @pageindex <= 0 begin set @pageindex = 1 end set @strsql='select top '+str(@pagesize)+' * from ' + @tbname + ' where id>(select max(id) from (select top '+str((@pageindex-1)*@pagesize)+' id from ' + @tbname + ''+@strorder+')a) '+@strorder+'' exec sp_executesql @strsqlcount,n'@totalcout int output',@total output exec(@strsql)
园子里搜到max/top这么一个版本,看起来很强大,
调用:
declare @count int --exec [dbo].[spsqlpagebyrownumber]'pagetest','*',50,20,'','order by id asc',@count output exec [dbo].[spsqlpagebymaxtop]'pagetest','*',50,20,'','order by id asc',@count output select @count
以上就是本文针对sql分页查询几种写法的全部内容,希望大家喜欢。
上一篇: 使用haproxy实现负载均衡集群