简单的说就是这个
select top(20) * from(
select *, rowid = row_number() over(order by xxx) from tb with(nolock)
) data where rowid > 0
order by rowid
或者这样写
select * from(
select *, rowid = row_number() over(order by xxx) from tb with(nolock)
) data where rowid > 0 and rowid <= 20
以前有强调,对于这类查询,一定要使用下面这样的方式(或者类似的,主要就是先取出满足条件的主键),但从这个邮件看,大家还在使用前面的老方法
--推荐方法:
select * from tb with(nolock)
where 主键 in(
select 主键 from(
select 主键, rowid = row_number() over(order by xxx) from tb with(nolock)
) data where rowid > 0 and rowid <= 20
)
之前一下强调这样做的原因是性能,因为旧的方法,数据是在 ROW_NUMBER 的时候同时取的,也就是分页前,实际上是取了所有数据,只是最终只返回了一部分而已
现在新发现的问题是:
当表包含一些长度较大的字段,比如 xml, varchar/nvarchar(max),或者是长度几千的(比如邮件中的这个表就有几个是 8000的)
内存开销的评估可能会变得很恐怖,为查询分配的内存会达到一个很大的值,比如这个查询,内存的分配是 4.4G, 我们的服务器也就64G内存,10来个这样的查询并发就会导致服务器因为没有可用内存而无法响应后续的请求
所以衣大家特别注意,这个附件中的查询请安排相关的人员调整
附件有一个是之前调整的,那个更恐怖,按10G的内存
降低内存开销主要是在 ORDER BY,包括 ROW_NUMBER 这种有 ORDER BY 操作的排名函数使用时,尽量在在查询的列中中排除掉无关列,特别是 xml, nvarchar/varchar 这种长度较长的列(不管这些列是否包含数据,只要定义够长就应该避免;内存评估是根据结构,不是根据实际存储的数据)