zoukankan      html  css  js  c++  java
  • 几种常见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万:

    100万:

    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() 的变体基于我这个测试效率实在不好。原帖在这里 http://topic.csdn.net/u/20100617/04/80d1bd99-2e1c-4083-ad87-72bf706cb536.html

    PS.上面的分页排序都是基于自增字段id。测试环境还提供了int,nvarchar,datetime类型字段,也可以试试。不过对于非主键没索引的大数据量排序效率应该是很不理想的。

    5.简单将ROWNUMBER,max/top的方式封装到存储过程。

    ROWNUMBER():

    create proc [dbo].[spSqlPageByRownumber]
    @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 * from (Select row_number() over('+@strOrder+') rowId,'+ @tbFields
    +' from ' + @tbName + ' where 1=1 ' + @strWhere+' ) tb where tb.rowId >'+str((@PageIndex-1)*@PageSize)
    +' and tb.rowId <= ' +str(@PageIndex*@PageSize)

    exec sp_executesql @strSqlCount,N'@TotalCout int output',@Total output
    exec(@strSql)

    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这么一个版本,看起来很强大,http://www.cnblogs.com/hertcloud/archive/2005/12/21/301327.html

    调用:

    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
  • 相关阅读:
    Calling a parent window function from an iframe
    JSON with Java
    Posting array of JSON objects to MVC3 action method via jQuery ajax
    What's the difference between jquery.js and jquery.min.js?
    jquery loop on Json data using $.each
    jquery ui tabs详解(中文)
    DataTables warning requested unknown parameter
    Datatables 1.10.x在命名上与1.9.x
    jQuery 1.x and 2.x , which is better?
    DataTabless Add rows
  • 原文地址:https://www.cnblogs.com/zxktxj/p/2334309.html
Copyright © 2011-2022 走看看