以  项目表 PM_Project  为例。

  PM_Project 全部内容如下(共6条数据):

一、Top – Not In - Top 方式分页

直接的,原始的,不采用函数,纯手动挡。

分步探索过程:

  采用的最直接做法就是使用两个Top来实现。

DECLARE  @pageSize INT =4,@pageIndex INT =1
BEGIN
SELECT TOP (@pageSize)
*
FROM ( SELECT TOP (@pageSize * @pageIndex)
*
FROM PM_Project
ORDER BY Id DESC --- 内查询倒序
) AS temp
ORDER BY Id ---外查询正序, 内外查询顺序不一致即可
END
GO

结果:

乍一看是没有问题的,但是仔细一看会发现其中存在的问题。当符合条件的纪录集小于每页记录数时,没有问题,但是当大于就有问题了。

例如上边代码,实际满足条件的是6条,即全部满足(因为根本就没加条件)。第一页是没有问题的,但是第二页就有问题了。现在共6条数据,每页4条,按理说第二页应该只有2条。但是使用如上的方法,每次都会返回4条记录。

当pageIndex =2 时,结果如下:

沿用上面的思路,把代码修改为了采用三层查询,最内一层查询所有满足条件的数据,然后第二层选择Top PageSize个所有NOT IN 第一层数据中的数据即可,因为使用了NOT IN所以不存在第一种方法中的bug

DECLARE  @pageSize INT =4,@pageIndex INT =2  ---直接看第二页
BEGIN SELECT *
FROM PM_Project
WHERE Id IN (
SELECT TOP ( @pageSize )
Id
FROM PM_Project
WHERE Id NOT IN ( SELECT TOP ( @pageSize * (@pageIndex-1) )---去除本页之前的所有id
Id
FROM PM_Project
ORDER BY Id)
ORDER BY PM_Project.Id)
ORDER BY PM_Project.Id ASC END
GO

结果:

二、ROW_NUMBER()的方式实现分页

语法:  

ROW_NUMBER ( ) OVER ( [ PARTITION BY value_expression , ... [ n ] ] order_by_clause )

分步过程:

首先查询全部满足条件的数据,并使用 ROW_NUMBER() 函数,可以根据给定好的排序字段规则,为查询结果生成记录序号。

SELECT ROW_NUMBER() OVER (ORDER BY id) rownum,
    *
FROM PM_Project

结果:(共6条数据)

然后用TOP()函数取出一页数据

DECLARE  @pageSize INT =4,@pageIndex INT =1  ------每页4条,第一页
BEGIN SELECT TOP(@pageSize*@pageIndex)
ROW_NUMBER() OVER (ORDER BY id) rownum,
*
FROM PM_Project
END
GO

这样取第一页还是可以的,但是往后就会越来越多。现在将上边的查询作为内查询,再外查询中通过条件来控制获取页数问题。

策略很简单,首先我们选取包含要查页的数据,然后使用ROW_NUMER函数进行编号, 然后在外查询中指定rownum大于页起始记录即可。这种方式简单快捷。

DECLARE  @pageSize INT =4,@pageIndex INT =2  ------每页4条,第二页
BEGIN
SELECT*FROM
(
SELECT TOP(@pageSize*@pageIndex)
ROW_NUMBER() OVER (ORDER BY id) rownum,*
FROM PM_Project
)temp
WHERE temp.rownum>(@pageSize*(@pageIndex-1))
END
GO

查询第二页的结果:

在 Sql Server 2000 之后的版本中,ROW_NUMBER() 这种分页方式一直都是很不错的,比起之前的游标分页,性能好了很多,因为 ROW_NUMBER() 并不会引起全表扫表,但是,语法比较复杂,并且,随着页码的增加,性能也越来越差。

三、使用CTE(common_table_expression,公用表表达式)的方式

使用很简单,就是把内查询放在CTE 里面。

DECLARE  @pageSize INT =4,@pageIndex INT =2
BEGIN
WITH temp
AS ( SELECT TOP ( @pageSize * @pageIndex )
ROW_NUMBER() OVER ( ORDER BY id) AS rownum ,
*
FROM PM_Project
)
SELECT *
FROM temp
WHERE temp.rownum > ( @pageSize * ( @pageIndex - 1 ) )
ORDER BY temp.Id
END
GO

结果:

四、使用 OFFSET  FETCH 子句分页

语法:

OFFSET { integer_constant | offset_row_count_expression } { ROW | ROWS }

FETCH { FIRST | NEXT } { integer_constant | fetch_row_count_expression } { ROW | ROWS } ONLY

从语法可以看出来 两个方法 后面不但能接 intege 类型的参数,还能接 表达式的,比如  1*2 +3 之类的,同时, Row 或者 Rows 是不区分大小写和单复数的。

SQL Server 2012及以后版本支持。

例句:

DECLARE  @pageSize INT =4,@pageIndex INT =2
BEGIN SELECT*FROM PM_Project
ORDER BY Id
OFFSET ( @pageSize * ( @pageIndex - 1 )) ROWS
FETCH NEXT @pageSize ROWS ONLY END
GO

结果:

性能对比:

  在 Sql Server 2012 里面,分页方法中,Offset and Fetch 同 ROW_NUMBER() 比较起来,无论是性能还是语法,都是有优势的。
  但是性能方面,优势并不是太大,两者 的 IO 消耗完全相同。
  只是 在 CPU 方面,Offset and Fetch 方面要好一些,但是不明显。
  如果对于一个 每秒都要处理成千上万条的分页Sql语句的DB 来说,Offset and Fetch 在CPU 方面的优势会比较明显的,否则,性能的提升并不明显。

SQLServer数据库分页的更多相关文章

  1. Sqlserver数据库分页查询

    Sqlserver数据库分页查询一直是Sqlserver的短板,闲来无事,想出几种方法,假设有表ARTICLE,字段ID.YEAR...(其他省略),数据53210条(客户真实数据,量不大),分页查询 ...

  2. MySQL、SqlServer、Oracle三大主流数据库分页查询

    在这里主要讲解一下MySQL.SQLServer2000(及SQLServer2005)和ORCALE三种数据库实现分页查询的方法.可能会有人说这些网上都有,但我的主要目的是把这些知识通过我实际的应用 ...

  3. 【转载】Sqlserver数据库中无自增Id的情况下使用ROW_NUMBER()函数进行数据分页

    在Sqlserver数据库中,如果查询表中含有自增长Id列,一般会采用select Top的方式来数据的分页操作.而实际上很多数据表设计的时候,不一定含有自增长Id列,那么数据库没有Id自增列的时候要 ...

  4. mysql / sqlserver / oracle 常见数据库分页

    空闲时间里用着mysql学习开发测试平台和测试用具, 在公司里将可用的测试平台部署,将数据库换成sqlserver 巴望着能去用oracle的公司 mysql中的分页 limit是mysql的语法se ...

  5. MySQL、SqlServer、Oracle三大主流数据库分页查询 (MySQL分页不能用top,因为不支持)

    一. MySQL 数据库 分页查询MySQL数据库实现分页比较简单,提供了 LIMIT函数.一般只需要直接写到sql语句后面就行了.LIMIT子 句可以用来限制由SELECT语句返回过来的数据数量,它 ...

  6. 浅谈SQL Server数据库分页

    数据库分页是老生常谈的问题了.如果使用ORM框架,再使用LINQ的话,一个Skip和Take就可以搞定.但是有时由于限制,需要使用存储过程来实现.在SQLServer中使用存储过程实现分页的已经有很多 ...

  7. sqlserver 存储过程分页管理

    -- =============================================-- Author:  <Author:刘畅>-- Create date: <Cre ...

  8. Oracle、MySql、SQLServer数据分页查询

    看过此博文后Oracle.MySql.SQLServer 数据分页查询,在根据公司的RegionRes表格做出了 SQLserver的分页查询语句: 别名.字段 FROM( SELECT row_nu ...

  9. SQL多表连接查询以及mysql数据库、sqlserver数据库常见不同点

    mysql数据库表及数据准备语句: USE test; DROP TABLE IF EXISTS `teacher_table`; DROP TABLE IF EXISTS `student_tabl ...

随机推荐

  1. 爬楼梯的golang实现

    假设你正在爬楼梯.需要 n 阶你才能到达楼顶. 每次你可以爬 1 或 2 个台阶.你有多少种不同的方法可以爬到楼顶呢? 注意:给定 n 是一个正整数. 输入: 输出: 解释: 有两种方法可以爬到楼顶. ...

  2. ElasticSearch(三):Java操作ElasticSearch索引之CRUD

    package com.gxy.ESChap01; import java.net.InetAddress; import java.util.HashMap; import java.util.Ma ...

  3. spring jwt springboot RESTful API认证方式

    RESTful API认证方式 一般来讲,对于RESTful API都会有认证(Authentication)和授权(Authorization)过程,保证API的安全性. Authenticatio ...

  4. day 03 基本数据类型的使用、运算符

    一:基本数据类型的使用 1.为什么数据要区分类型 数据类型指的是变量值的类型,变量值是用来记录事物的状态的,而事物的状态具有不同的类型,不同类型的变量值表示不同类型的状态,所以数据要区分类型. 2.数 ...

  5. camke使用例程

    1 同文件夹直接编译 1 同文件夹直接编译 # cmake needs this line cmake_minimum_required(VERSION 2.8) # Define project n ...

  6. Vim 安装 YouCompleteMe

    Vim 下的自动补全,最好的工具莫过于 YouCompleteMe,官方文档在这里 http://valloric.github.io/YouCompleteMe/ 安装稍显复杂,以下记录我的过程. ...

  7. appium遇到click事件,提示"w3cStatus":400

    1.小米手机被开发借用后归还,使用该手机再进行自动化,发现appium遇到click事件,返回400 2.当时未想到是要在手机侧进行开发者选项-调试权限的设置 3.一直以为是appium的问题,app ...

  8. Node.js读取某个目录下的所有文件夹名字并将其写入到json文件

    针对解决的问题是,有些时候我们需要读取某个文件并将其写入到对应的json文件(xml文件也行,不过目前用json很多,json是主流). 源码如下:index.js var fs = require( ...

  9. OpenCV3计算机视觉Python语言实现笔记(二)

    1. 图像与原始字节之间的转换 从概念上讲,一个字节能表示0到255的整数.目前,对于多有的实时图像应用而言,虽然有其他的表示形式,但一个像素通常由每个通道的一个字节表示. 一个OpenCV图像是.a ...

  10. python 自动获取星期

    自动获取星期: >>> from time import time,localtime,strftime>>> x=localtime(time())>> ...