SQLServer分页功能性能优化

1. 基础数据

         RtlBill行数: 54754
         RtlDetail行数:4723291

         如果不分页,结果集行数:198


2. 常用的分页方式:用 With + Row_Number() 来取分页数据

  

    dbcc dropcleanbuffers;
   declare@begin int = 10;
   declare@endint= 20;
   set statistics io on;
    set statistics time on;

    ;witha as
    (
        SELECTBillDate,SUM([QTY]) PosInQty, row_number() over(order by billdate) as id
        FROMRtlDetail Ainner join RtlBill B  on (A.billno = B.billno)
        GROUP BY BillDate
    )
   select* from a whereid>@begin andid<=@end;
   set statistics io off;
    set statistics time off;


(10 行受影响)
表 'RtlBill'。扫描计数 17,逻辑读取 496 次,物理读取 1 次,预读 165 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'RtlDetail'。扫描计数 17,逻辑读取 49888 次,物理读取 3 次,预读 49284 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'Worktable'。扫描计数 0,逻辑读取 0 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

 SQL Server 执行时间:
   CPU 时间 = 4767 毫秒,占用时间 = 5880 毫秒。


     从IO及CPU时间可以看出,这个分页SQL消耗资源多,耗时长,下面通过执行计划来分析一下原因,寻找优化方法;


2. 执行计划分析


(1)从执行计划中,可以看到大量使用并行处理;

(2)红色圈出的“哈希匹配”部分,详情,如下图,其中可以看到,实际行数为198行,也就是未分页的完整结果的行数,为什么SQLServer不能在取到30行后就停止执行,直接返回呢?

              

(3)接着看红色圈出的“并行度”部分,详情如下图。SQLServer在进行多线程处理的时候,使用的任务分配方法,一般为Hash,或RoundRobin方式。Hash方式即对数据做Hash计算,来确定究竟传给哪个线程处理,RoundRobin为轮询方式。每个线程之间没有消息通讯。这样导致,在所有线程完成全部处理之前,系统无法获知究竟是否取到了所要获取的分页中的所有数据。那么,如果我们使用单线程的方式,并且在With语句内部就用TOP的方式告诉SQLServer,我只要获取@end条记录就可以了,是否就可以让SQLServer做出正确的相应呢?

               


3. 依据前面的分析,改进分页数据获取语句

   注意:这里需要用SQL拼接的方式直接把行数拼接进语句中,否则,生成执行计划时,SQL无法预估结果集。

              呵呵,关于参数的问题,单独一篇来分析。

   dbcc dropcleanbuffers;
  set statistics io on;
    set statistics time on;

    ;witha as
    (
        SELECT  Top 20  BillDate, SUM([QTY]) PosInQty,row_number() over(order bybilldate) as id
        FROMRtlDetail Ainner join RtlBill B  on (A.billno = B.billno)
        GROUP BY BillDate
    )
   select* from a whereid>10 option(maxdop 1);
   set statistics io off;
    set statistics time off;


4. 实验结果对比


5. 不适用的情况

(1)使用 Dense_Rank()等函数进行分页时,不能使用TOP方式(因为,结果行数都不同);

(2)需要大量计算的SQL(这个需要实际分析,如果CPU耗时太多,单线程处理的优势就体现不出来了)。


6. 优化策略

(1)如果你的分页查询有性能问题

        尝试Top+SingleThread的方式。有效?OK

›(2)提升不明显?计划中有大量计算?

        折中一下,单独使用Top方式

(3)›还是无提升?且是关联查询?

        尝试,用count(*) Over()优化首页











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值