Sql Server 2012 的新分页方法分析(offset and fetch) - 转载

最近在分析 Sql Server 2012 中 offset and fetch 的新特性,发现 offset and fetch 不管语法的简洁仍是功能的强大,都是至关至关不错的express

 

其中 offset and fetch 最重要的新特性是 用来 分页,既然要分析 分页,就确定要和以前的分页方式来比较了,特别是 Row_Number() 了,在比较过程当中,发现了蛮多,不过最重要的,经过比较本质,得出了优劣,也和你们一块儿分享下。
准备工做,创建测试表:Article_Detail,主要是用来存放一些文章信息,测试的时间,都是从网易上面转载的新闻,同时,测试表数据字段类型是比较均匀的,为了更好的测试,表结构以下图: 函数

 

表数据:oop

数据量:129,991 条记录性能

 

语法分析测试

1. NTILE() 的分页方法fetch

NTILE() 方法能够用来分页,可是应用场景十分的狭窄,而且性能差劲,和 Row_Number() 与 offset fetch 分页比起来没有任何优点,也只有在只读表上面分页的话,仍是比较合适的;虽然很差用,可是还能来分页的,因此只简单的介绍下。spa

语法:3d

NTILE (integer_expression) OVER ( [ <partition_by_clause> ] < order_by_clause > ) 将有序分区中的行分发到指定数目的组中。 各个组有编号,编号从一开始。 对于每个行,NTILE 将返回此行所属的组的编号。code

测试中用到的 Sql 语句 :blog

1 set statistics time on 
2 set statistics io on 
3 set statistics profile on; 
4 with #pager as 
5 ( 
6 select ID,Title,NTILE(8666) OVER(Order By ID) as pageid from Article_Detail 
7 ) 
8 select ID,Title from #pager where pageid=50 
9 set statistics profile on;

其中上述数字中的 8666 是根据 RowCount / Pagesize 计算出来的,不过多介绍,能够自行参考 MSDN的

 

2. ROW_NUMBER() 的分页方法

在 Sql Server 2000 以后的版本中,ROW_NUMBER() 这种分页方式一直都是很不错的,比起以前的游标分页,性能好了不少,由于 ROW_NUMBER() 并不会引发全表扫表,可是,语法比较复杂,而且,随着页码的增长,性能也愈来愈差。 语法 : ROW_NUMBER ( ) OVER ( [ PARTITION BY value_expression , ... [ n ] ] order_by_clause ) 测试中用到的 Sql 语句:

 1 dbcc freeproccache 
 2 dbcc dropcleanbuffers 
 3 set statistics time on 
 4 set statistics io on 
 5 set statistics profile on; 
 6 with #pager as 
 7 ( 
 8 select ID,Title,ROW_NUMBER() OVER(Order By ID) as rowid from Article_Detail 
 9 ) 
10 select ID,Title from #pager where rowid between (15 * (50-1)+1) and 15 * 50 
11 set statistics profile off;

 

3. Offset and Fetch 的分页方法 (从Sql Server 2012开始支持该语法)
语法:
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 语句,真的是简洁的不能再简洁了,看两遍都能记住的语法,分页能够如此的简洁:

1 dbcc freeproccache 
2 dbcc dropcleanbuffers 
3 set statistics time on 
4 set statistics io on 
5 set statistics profile on; 
6 select ID,Title from Article_Detail order by id OFFSET (15 * (50-1)) ROW FETCH NEXT 15 rows only --通过测试offset and fetch语法必须跟在order by后面用,不然会报语法错误,也就是说offset and fetch语法和row_number函数同样,须要用到一列数据来排序
7 set statistics profile off;

一句就搞定!

 


性能比较
1. NTILE() 的执行计划

从执行计划中,就能够看出来,进行了一次全表扫表,两次 Nested Loops ,还有无数其余运算,就一次全表扫表,就知道性能之差了

 

2. ROW_NUMBER() 的执行计划

从执行计划中能够看出来, 汇集索引扫描占用了100% 的资源,可是经过 EstimateRows = 100 和 Rows = 750 能够看出来,并无进行全表扫描,而且IO 操做很小,因此性能仍是很不错的

 

3. Offset and Fetch 的 执行计划

执行计划只有3行,而且占用资源 100% 的IO 操做 ,EstimateRows = 100 和 Rows = 750 是和 ROW_NUMBER() 彻底同样的,可是其余的一些操做却少了不少,也就是说,并无全表扫描,并下降了CPU 的消耗。

 

 

综合比较: 在 Sql Server 2012 里面,分页方法中,Offset and Fetch 同 ROW_NUMBER() 比较起来,不管是性能仍是语法,都是有优点的。 可是性能方面,优点并非太大,二者 的 IO 消耗彻底相同,只是 在 CPU 方面,Offset and Fetch 方面要好一些,可是不明显。若是对于一个 每秒都要处理成千上万条的分页Sql语句的DB 来讲,Offset and Fetch 在CPU 方面的优点会比较明显的,不然,性能的提高并不明显。 语法方面 Offset and Fetch 则是十分的简洁,一句搞定,比起 Row_Number() 好了太多 ~ 同是 Offset and Fetch 并不只仅能够用来分页哦,具体其余使用,你们能够自行参考 MSDN

相关文章
相关标签/搜索