一、引入
通过前面的查询学习,我们知道,查询有DataReader和DataSet两种方式。不同的是,前者查询出来的结果集是放在数据库服务器上的,我们每次只能只进一条一条的读取数据,而且在读取的过程中,数据库必须是打开的。后者是把数据库服务器上的结果集保存到本地应用程序内存中,注意,此时是把从数据库服务器上查询到的结果集都放到本地内存中了。如果数据量不大,无所谓,可要是很大的话就会很占用本地内存,甚至造成本地内存的溢出。(C/S架构的项目中,本地的内存一般都是够用的;B/S架构的项目中,用户的并发访问量很大,如果针对每个用户的查询请求都把结果集放到本地,这对应用程序服务器内存该是多么可怕的一件事情啊。)个人认为,对应C/S架构的项目,两种读取方式都可以,对于B/S架构的项目,最好使用前者。
前面讲的是数据库数据的完全查询,现实中,客户还需要进行部分查询。如,我只需要第三页的数据,其他的我都不需要,这个时候就牵扯到数据的分页查询了。
二、基础知识
分页有高效和低效两种高效:先在数据库中对数据分页,之后根据sql语句进行对应页数数据集的查询
低效:把结果集都查询出来放到本地,再对本地中的结果集进行分页、查询
第一种方法就不用我多说了,可以减轻服务器压力、降低网络负载、节省内存等。第二种方法就是一种出力不讨好的做法,具体不再累述,相信大家也都能理解。
三、分页方法
现在主要针对第一种分页进行高效分页方法的学习
分页有两种做法:(1)子查询
可以在所有版本的数据库,通过子查询来做 查询出n-1页的数据作为子查询结果
select top 10 * from dbo.Publish
where PNO not in
(
select PNO from dbo.Publish
where PNO between 11 and 20
)
--公式化 设要查询第n页,页大小为p
select top p * from 表名
where 主键 not in
(select top (n-1)*p 主键 from表名
)
简单点理解就是你需要21~30之间的10条数据,那我就查询出前30条数据,再把之前1~19之间的数据排除掉,就可以得到21~30之间的10条数据
(2)函数 Row_Number()
在2005(含)以后的版本中存在
--为我们的每一行产生一个编号 疑问点:为何要指定主键意外的列进行排序
select * from dbo.Publish
大家通过上面图片的红色标注应该看出来了,我们把所有的数据都查询出来时也能在左侧产生一个编号,可问题是这个编号我们能用吗?
select * from(
select *,ROW_NUMBER() over(order by PName) as [序号]
from dbo.Publish
) as t
where 序号 between 1 and 10
上面就是通过执行Row_Number()得到的结果,我们可以看到在右侧增加了一列:序号 他是从1开始排序的,无论之前的数据是怎么样,当我们在上面的sql语句中通过over语句定义过排序规则并确定好列名之后,新产生的列的编号都是从1开始的。
--公式化 查询第n页,每页大小为p
select * from
(
select * ,ROW_NUMBER() over(order by 排序字段) as 别名
from 表名
)as t
where 别名 between (n-1)*p+1 and n*p
注:
(1)上面写的都是select * 查询所有字段,当然也可以查询部分字段
(2)使用Row_Number()函数的时候一定要带上over()
(3)over(order by 字段)中的字段可以选择升序也可以选择降序,还可以选择按多个字段进行排序