一直想整理下关于sql分页的几种方法,今天终于有时间整理下了。闲话少说直接上sql,先创建一个测试库,测试表以及测试数据,sql语句如下:

CREATE DATABASE DBTEST
GO
USE DBTEST
GO
--创建测试表
create table pagetest
(
id int identity(1,1) not null,
col01 int null,
col02 nvarchar(50) null,
col03 datetime null
) --100万记录集 耗时 3'46''
declare @i int
set @i=0
while(@i<1000000)
begin
insert into pagetest select cast(floor(rand()*1000000) as int),left(newid(),10),getdate()
set @i=@i+1
END

在pagetest表里面插入了1000000条记录,共耗时3'46'',当然这跟电脑配置有关。主要说以下几种方法:

为了方便定义两个参数,一个是页的大小@PageSize,一个是@PageIndex页的索引。

DECLARE @pageIndex INT, -----页索引

@pageSize INT  -----页大小

我们设置每页大小为500条,取@pageIndex=198 即199页数据,

SET @pageSize=500

SET @pageIndex=198

下面直接上几种常用的sql分页的方法:为了测试每种方法的执行时间,定义一个开始时间和结束时间

DECLARE @begin_date DATETIME;
DECLARE @end_date DATETIME;
SELECT @begin_date = GETDATE(); DECLARE @pageIndex INT, -----页索引
@pageSize INT -----页大小 SET @pageSize = 500;
SET @pageIndex = 198; ----写法一 NOT IN /Top
SET @begin_date = GETDATE(); SELECT TOP (@pageSize)
*
FROM dbo.pagetest
WHERE id NOT IN
(
SELECT TOP (@pageSize * @pageIndex) id FROM dbo.pagetest ORDER BY id ASC
)
ORDER BY id ASC; SELECT @end_date = GETDATE();
SELECT 'NOT IN /Top' AS 'Type',
DATEDIFF(ms, @begin_date, @end_date) AS '毫秒'; ----写法二 NOT EXIST
SET @begin_date = GETDATE(); SELECT TOP (@pageSize)
*
FROM dbo.pagetest p
WHERE NOT EXISTS
(
SELECT 1
FROM
(
SELECT TOP (@pageSize * @pageIndex)
*
FROM dbo.pagetest p
ORDER BY p.id ASC
) a
WHERE p.id = a.id
)
ORDER BY id ASC; SELECT @end_date = GETDATE();
SELECT 'NOT EXIST' AS 'Type',
DATEDIFF(ms, @begin_date, @end_date) AS '毫秒'; ----写法三 MAX/TOP
SET @begin_date = GETDATE(); SELECT TOP (@pageSize)
*
FROM dbo.pagetest
WHERE id >
(
SELECT MAX(id)
FROM
(
SELECT TOP (@pageSize * @pageIndex)
*
FROM dbo.pagetest
ORDER BY id ASC
) a
)
ORDER BY id ASC; SELECT @end_date = GETDATE();
SELECT 'MAX/TOP' AS 'Type',
DATEDIFF(ms, @begin_date, @end_date) AS '毫秒'; ----写法四 ROW NUMBER()
SET @begin_date = GETDATE(); SELECT TOP (@pageSize)
a.*
FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY id ASC) rowNum,
*
FROM dbo.pagetest
) a
WHERE a.rowNum > (@pageSize * @pageIndex)
ORDER BY a.id; SELECT @end_date = GETDATE();
SELECT 'ROW NUMBER()一' AS 'Type',
DATEDIFF(ms, @begin_date, @end_date) AS '毫秒'; SET @begin_date = GETDATE(); SELECT a.*
FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY id ASC) rowNum,
*
FROM dbo.pagetest
) a
WHERE a.rowNum > (@pageSize * @pageIndex)
AND a.rowNum < (@pageSize * @pageIndex + @pageSize + 1)
ORDER BY a.id; SELECT @end_date = GETDATE();
SELECT 'ROW NUMBER()二' AS 'Type',
DATEDIFF(ms, @begin_date, @end_date) AS '毫秒'; SET @begin_date = GETDATE(); SELECT a.*
FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY id ASC) rowNum,
*
FROM dbo.pagetest
) a
WHERE a.rowNum
BETWEEN (@pageSize * @pageIndex + 1) AND (@pageSize * @pageIndex + @pageSize)
ORDER BY a.id; SELECT @end_date = GETDATE();
SELECT 'ROW NUMBER()三' AS 'Type',
DATEDIFF(ms, @begin_date, @end_date) AS '毫秒'; ----写法五 ROWNUMBER()变体
SET @begin_date = GETDATE(); SELECT *
FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY tempColumn) AS rowNum,
*
FROM
(
SELECT TOP (@pageIndex * @pageSize + @pageSize)
tempColumn = 0,
*
FROM pagetest
WHERE 1 = 1
ORDER BY id ASC
) a
) b
WHERE b.rowNum > (@pageIndex * @pageSize); SELECT @end_date = GETDATE();
SELECT 'ROW NUMBER()变体' AS 'Type',
DATEDIFF(ms, @begin_date, @end_date) AS '毫秒'; ----写法六 OFFSET mssql2012后支持
SET @begin_date = GETDATE();
SELECT *
FROM dbo.pagetest
ORDER BY id ASC
OFFSET @pageIndex * @pageSize ROWS FETCH NEXT @pageSize ROWS ONLY; SELECT @end_date = GETDATE();
SELECT 'OFFSET' AS 'Type',
DATEDIFF(ms, @begin_date, @end_date) AS '毫秒';

大体看一下几种方法的执行速度,

执行多次后大体可以看出Max Top,RowNum()以及offset的执行效率比较高,RowNum()应该是在sql2005后就支持了,而offset是从sql2012开始支持。将以上两种常用的方法封装成存储过程:一个是RowNum() 一个是MaxTop

USE [DBTEST]
GO /****** Object: StoredProcedure [dbo].[Proc_SqlPageByRownumber] Script Date: 2017/4/21 16:24:52 ******/
SET ANSI_NULLS ON
GO SET QUOTED_IDENTIFIER ON
GO -- =============================================
-- Author: Allen
-- Create date: 2017-04-19
-- Description: 根据RowNumber()分页
-- =============================================
CREATE 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
DECLARE @strSql VARCHAR(5000); --主语句
DECLARE @strSqlCount NVARCHAR(500); --查询记录总数主语句
DECLARE @strOrder VARCHAR(300); -- 排序类型
BEGIN
--------------总记录数---------------
IF ISNULL(@strWhere, '') <> ''
SET @strSqlCount = 'Select @TotalCout=count(1) from ' + @tbName + ' where 1=1 ' + @strWhere;
ELSE
SET @strSqlCount = 'Select @TotalCout=count(1) 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; GO
USE [DBTEST]
GO /****** Object: StoredProcedure [dbo].[ProcSqlPageByMaxTop] Script Date: 2017/4/21 16:27:11 ******/
SET ANSI_NULLS ON
GO SET QUOTED_IDENTIFIER ON
GO -- =============================================
-- Author: Allen
-- Create date: 2017-04-19
-- Description: MaxTop
-- =============================================
CREATE PROCEDURE [dbo].[ProcSqlPageByMaxTop]
@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); --查询记录总数主语句
BEGIN
--------------总记录数---------------
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);
END; GO
ish

以上也只是对单表的查询,注意在sql优化时要加上主键和索引,查询效率会提高,关于如何创建索引,在哪些字段时创建索引在下一篇博客中说明。

sql分页的几种写法的更多相关文章

  1. sql 分页的两种写法

    string Strsql = string.Format(@"select ee.DOCUMENTNO,ee.APPLICANTNAME,ee.COMPANY,ee.REQUESTTIME ...

  2. sql语句有几种写法

    sql语句有几种写法 1:SELECT * FROM tablename ORDER BY RAND() LIMIT 想要获取的数据条数: 2:SELECT *FROM `table` WHERE i ...

  3. Sql函数的三种写法

    以前复制的创建sql函数比较乱,现在将我自己项目中的三种sql函数做下对比,一目了然: (1)表值函数——方法一:直接创建临时表,并返回临时表.优点:函数体中间可以直接申明临时变量,并做各种逻辑处理, ...

  4. SQL分页的几种方式

    1.使用Row_number() over(order by columnName)函数来作为标示分页(下面的例子都是以last_seen来排序的,要求取顺序为20-30行的数据) SELECT Us ...

  5. SQL 循环语句几种写法

    1.正常循环语句 declare @orderNum varchar(255)create table #ttableName(id int identity(1,1),Orders varchar( ...

  6. 查询分页的几种Sql写法

    查询分页的几种Sql写法 摘自:http://www.cnblogs.com/zcttxs/archive/2012/04/01/2429151.html 1.创建测试环境,(插入100万条数据大概耗 ...

  7. 服务器文档下载zip格式 SQL Server SQL分页查询 C#过滤html标签 EF 延时加载与死锁 在JS方法中返回多个值的三种方法(转载) IEnumerable,ICollection,IList接口问题 不吹不擂,你想要的Python面试都在这里了【315+道题】 基于mvc三层架构和ajax技术实现最简单的文件上传 事件管理

    服务器文档下载zip格式   刚好这次项目中遇到了这个东西,就来弄一下,挺简单的,但是前台调用的时候弄错了,浪费了大半天的时间,本人也是菜鸟一枚.开始吧.(MVC的) @using Rattan.Co ...

  8. [转]几种常见SQL分页方式

    创建环境: create table pagetest ( id ,) not null, col01 int null, col02 ) null, col03 datetime null ) -- ...

  9. .net连接sql server的几种连接字符串的写法

    .net连接sql server的几种连接字符串的写法 1, 混合验证模式登录 server=电脑名 或 电脑IP;database=数据库名;uid=数据库登录名;password=数据库登录密码 ...

随机推荐

  1. Webshell清除-解决驱动级文件隐藏挂马

    Webshell清除-解决驱动级文件隐藏挂马

  2. Android 4.4 Kitkat 音频实现及简要分析

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/jingxia2008/article/details/26701899 在 Android 4.4 ...

  3. Nginx配置参数说明

    一.主配置段1.正常运行必备的配置#运行用户和组,组身份可以省略user nginx nginx; #指定nginx守护进程的pid文件pid path/to/nginx.pid; #指定所有work ...

  4. Python基础(15)_python模块、包

    一.模块 1.什么是模块:一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀 模块的本质:模块的本质是一个py文件 2.模块分为三类:1)内置模块:2)第三方模块: ...

  5. FTP主动连接与被动连接

    FTP(File Transfer Protocol, FTP)是TCP/IP网络上两台计算机传送文件的协议,应用层的协议,它基于传输层, FTP是一个8位的客户端-服务器协议,能操作任何类型的文件而 ...

  6. LeetCode:二叉树的层次遍历||【107】

    LeetCode:二叉树的层次遍历||[107] 题目描述 给定一个二叉树,返回其节点值自底向上的层次遍历. (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历) 例如:给定二叉树 [3,9,2 ...

  7. 【鸟哥的Linux私房菜】笔记2

    Linux的应用 学习资源整理 安装记录 >< 1.Linux的应用: 网络服务器 数据库 学术机构的高效运算任务 嵌入式系统 ... 2.挂载与磁盘分区 学习资源整理 学习 1.书上的网 ...

  8. package.json字段简要解析

    name 必填 应用名称 version 必填 应用版本 description 选填 应用描述,多用于搜索,在npm search 时可以用到 keywords 选填 应用关键字,也多用于搜索 sc ...

  9. Windows10在待机状态时会卡屏的解决方案

    问题:Windows10在待机时,会出现卡屏(鼠标.键盘都无法操作,只能重启电脑),区别于平时我们看得比较多的花屏.蓝屏.黑屏. 原因:经过一段时间的待机,Windows10会进入到降电节能模式,由于 ...

  10. JAVAWeb学习总结(二)

    JavaWeb学习总结(二)——Tomcat服务器学习和使用(一) 一.Tomcat服务器端口的配置 Tomcat的所有配置都放在conf文件夹之中,里面的server.xml文件是配置的核心文件. ...