加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > MsSql教程 > 正文

一套新的SqlServer2005分页方案,很实用,很快!

发布时间:2020-12-12 14:40:56 所属栏目:MsSql教程 来源:网络整理
导读:感谢大家的讨论,我总结一下集中讨论的焦点: 1、为什么要使用row方案: 在oracle里有row_number虚列, mySql有limit关键字分页, 他们都有一个比较通用的分页方案, 使得hibernate等类似的程序可以拼接sql字符串提供通用的分页。 而sqlserver却没有这样的分
感谢大家的讨论,我总结一下集中讨论的焦点:

1、为什么要使用row方案:
在oracle里有row_number虚列,
mySql有limit关键字分页,
他们都有一个比较通用的分页方案,
使得hibernate等类似的程序可以拼接sql字符串提供通用的分页。
而sqlserver却没有这样的分页方案。
于是乎,本人稍稍改装row_number()over(order by )用法,获得了一个通用的分页方案。
如提供了sql如下:
SQL code
   
   
    
     
    
    select
    
     
    
    *
    
     
    
    from
    
     Student 
    
    where
    
     Age
    
    >
    
    18
    
     
    
    order
    
     
    
    by
    
     Age 
   
   

被row方案的分页程序处理后变成
(在select 后面添加 top 开始位置 0 __tc,在外层嵌套固定模式的查询sql)
SQL code
   
   
    
     
    
    select
    
     
    
    *
    
     
    
    from
    
     ( 
    
    select
    
     row_number()
    
    over
    
    (
    
    order
    
     
    
    by
    
     __tc__)__rn__,
    
    *
    
     
    
    from
    
     (
    
    select
    
     
    
    top
    
     开始位置
    
    +
    
    10
    
     
    
    0
    
     __tc__,
    
    *
    
     
    
    from
    
     Student 
    
    where
    
     Age
    
    >
    
    18
    
     
    
    order
    
     
    
    by
    
     Age)t )tt 
    
    where
    
     __rn__
    
    >
    
    开始位置 
   
   

这样就得到了拼接出通用的分页sql方案了。
并且经过本人测试发现,这套方案的运行速度不逊于任何一套其他方案。
其余各方面效率还有待考察,忘高人指点了。

2、row方案的排序:
row方案可以任意排序,
只要修改最内层的select排序即可,
应该来说是很简单易用的。
参考【追加说明1、】和【#80楼】。

3、row方案和普通row_number()方案的区别:
一般的row方案:
SQL code
   
   
    
     
    
    select
    
     
    
    *
    
     
    
    from
    
     (
    
    select
    
     
    
    top
    
     开始位置
    
    +
    
    10
    
     row_number()
    
    over
    
    (
    
    order
    
     
    
    by
    
     Id)__rn__,
    
    *
    
     
    
    from
    
     Student)t 
    
    where
    
     __rn__
    
    >=
    
    开始的位置 
   
   

使用了over(order by 表中的列),照成了必须由用户提供这个列,
而不容易使用分页程序生成分页sql(如hibernate分页)。
而row方案使用的是一个常数列tempColumn,值永远是0。
SQL code
   
   
    
     
    
    select
    
     
    
    *
    
     
    
    from
    
     ( 
    
    select
    
     row_number()
    
    over
    
    (
    
    order
    
     
    
    by
    
     TempColmun) 
    
    *
    
     
    
    from
    
     ( 
    
    select
    
     
    
    top
    
     开始的位置 
    
    0
    
     
    
    as
    
     TempColmun,
    
    *
    
     
    
    from
    
     Student 
    
    order
    
     
    
    by
    
     Id )tt)t 
    
    where
    
     rowNumber 
    
    >=
    
    开始的位置 
   
   

这个列是静态的,只是为了使用row_number()函数,
并不是真正的order by 依据,order by 实际看最内层。

我分析是因为row方案使用一个静态的列tempColumn,
这样可能被sql分析程序认为是无需排序的,省下了排序过程的开销。

4、数据测试:
现只在我一台机子上试过,
希望路过的各位随手帮忙测试一下。
这也是我迟迟不结贴的缘故。
举手之劳,复制sql运行即可:
SQL code
   
   
    
     
    
    --
    
    插入测试数据200w条,可能会很久
    
     
    
    create
    
     
    
    table
    
     Student( Id 
    
    int
    
     
    
    PRIMARY
    
     
    
    KEY
    
     
    
    identity
    
    (
    
    1
    
    ,
    
    1
    
    ),Name 
    
    nvarchar
    
    (
    
    50
    
    ),Age 
    
    int
    
     ) 
    
    insert
    
     Student(Name,Age)
    
    values
    
    (
    
    '
    
    Name
    
    '
    
    ,
    
    18
    
    ) 
    
    while
    
     (
    
    select
    
     
    
    count
    
    (
    
    *
    
    ) 
    
    from
    
     Student)
    
    <
    
    2000000
    
     
    
    insert
    
     Student 
    
    select
    
     Name,Age 
    
    from
    
     Student 
   
   

运行测试代码:
SQL code
   
   
    
     
    
    --
    
    开始测试查询
    
     
    
    declare
    
     
    
    @now
    
     
    
    datetime
    
     
    
    --
    
    max方案
    
     
    
    select
    
     
    
    '
    
    max
    
    '
    
    方案 
    
    select
    
     
    
    @now
    
    =
    
    getdate
    
    () 
    
    --
    
    begin
    
     
    
    select
    
     
    
    top
    
     
    
    10
    
     
    
    *
    
     
    
    from
    
     Student 
    
    where
    
     Id
    
    >
    
    ( 
    
    select
    
     
    
    max
    
    (Id) 
    
    from
    
     ( 
    
    select
    
     
    
    top
    
     
    
    1999990
    
     Id 
    
    from
    
     Student 
    
    order
    
     
    
    by
    
     Id)tt) 
    
    --
    
    end
    
     
    
    declare
    
     
    
    @maxDiff
    
     
    
    int
    
     
    
    select
    
     
    
    @maxDiff
    
    =
    
    datediff
    
    (ms,
    
    @now
    
    ,
    
    getdate
    
    ()) 
    
    --
    
    top方案
    
     
    
    select
    
     
    
    '
    
    top
    
    '
    
    方案 
    
    select
    
     
    
    @now
    
    =
    
    getdate
    
    () 
    
    --
    
    begin
    
     
    
    select
    
     
    
    top
    
     
    
    10
    
     
    
    *
    
     
    
    from
    
     Student 
    
    where
    
     Id 
    
    not
    
     
    
    in
    
    (
    
    select
    
     
    
    top
    
     
    
    1999990
    
     Id 
    
    from
    
     Student) 
    
    --
    
    end
    
     
    
    declare
    
     
    
    @topDiff
    
     
    
    int
    
     
    
    select
    
     
    
    @topDiff
    
    =
    
    datediff
    
    (ms,
    
    getdate
    
    ()) 
    
    --
    
    row方案
    
     
    
    select
    
     
    
    '
    
    row
    
    '
    
    方案 
    
    select
    
     
    
    @now
    
    =
    
    getdate
    
    () 
    
    --
    
    begin
    
     
    
    select
    
     
    
    *
    
     
    
    from
    
     ( 
    
    select
    
     row_number()
    
    over
    
    (
    
    order
    
     
    
    by
    
     tc)rn,
    
    *
    
     
    
    from
    
     (
    
    select
    
     
    
    top
    
     
    
    2000000
    
     
    
    0
    
     tc,
    
    *
    
     
    
    from
    
     Student)t )tt 
    
    where
    
     rn
    
    >
    
    1999990
    
     
    
    --
    
    end
    
     
    
    declare
    
     
    
    @rowDiff
    
     
    
    int
    
     
    
    select
    
     
    
    @rowDiff
    
    =
    
    datediff
    
    (ms,
    
    getdate
    
    ()) 
    
    --
    
    row_number方案
    
     
    
    select
    
     
    
    '
    
    row_number
    
    '
    
    方案 
    
    select
    
     
    
    @now
    
    =
    
    getdate
    
    () 
    
    --
    
    begin
    
     
    
    select
    
     
    
    *
    
     
    
    from
    
    ( 
    
    select
    
     
    
    top
    
     
    
    2000000
    
     row_number()
    
    over
    
    (
    
    order
    
     
    
    by
    
     Id)rn,
    
    *
    
     
    
    from
    
     Student )t 
    
    where
    
     rn
    
    >
    
    1999990
    
     
    
    --
    
    end
    
     
    
    declare
    
     
    
    @row_numberDiff
    
     
    
    int
    
     
    
    select
    
     
    
    @row_numberDiff
    
    =
    
    datediff
    
    (ms,
    
    getdate
    
    ()) 
    
    --
    
    记录结果
    
     
    
    select
    
     
    
    '
    
    第20万页
    
    '
    
    页码,
    
    @maxDiff
    
     max方案,
    
    @topDiff
    
     top方案,
    
    @rowDiff
    
     row方案,
    
    @row_numberDiff
    
     row_number方案 
   
   


-----------------------------------------------------------
以下为原帖:
-----------------------------------------------------------

这套方案(下面简称row方案)是本人借鉴Oracle的row_number分页方法和sqlServerrow_number结合+上top分页方案合体版,经过本人初步测试。
效率非常快。(本人测试非常业余,还望高人帮忙测试。)
row方案的具体操作方法在这章帖子里:
一套原创的sqlserver通用分页方案 忘高人测试效率 先阿里嘎多了

比较了3种分页方式,分别是max方案,top方案,row方案

效率:
? 第1:row
? 第2:max
? 第3:top

缺点:
? max:必须用户编写复杂Sql,不支持非唯一列排序
? top:必须用户编写复杂Sql,不支持复合主键
? row:不支持sqlServer2000

测试数据:
320万条数据,每页显示 10条数据,分别测试了 2万页、 15万页和 32万页。

页码, top方案max方案row方案
2万, 60ms46ms33ms
15万, 453ms343ms310ms
32万, 953ms720ms686ms


具体操作sql代码如下:

top方案:
SQL code
   
   
    
    select
    
     
    
    top
    
     
    
    10
    
     
    
    *
    
     
    
    from
    
     Table1 
    
    where
    
     Id 
    
    not
    
     
    
    in
    
    (
    
    select
    
     
    
    top
    
     开始的位置 Id 
    
    from
    
     Table1)
   
   

max:
SQL code
   
   
    
    select
    
     
    
    top
    
     
    
    10
    
     
    
    *
    
     
    
    from
    
     Table1 
    
    where
    
     Id
    
    >
    
    (
    
    select
    
     
    
    max
    
    (Id) 
    
    from
    
     (
    
    select
    
     
    
    top
    
     开始位置 Id 
    
    from
    
     Table1order 
    
    by
    
     Id)tt)
   
   

row:
SQL code
   
   
    
    select
    
     
    
    *
    
     
    
    from
    
     ( 
    
    select
    
     row_number()
    
    over
    
    (
    
    order
    
     
    
    by
    
     tempColumn)tempRowNumber,
    
    *
    
     
    
    from
    
     (
    
    select
    
     
    
    top
    
     开始位置
    
    +
    
    10
    
     tempColumn
    
    =
    
    0
    
    ,
    
    *
    
     
    
    from
    
     Table1)t )tt 
    
    where
    
     tempRowNumber
    
    >
    
    开始位置
   
   

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读