簡介
SQL Server 2012中在Order By子句之后新增了OFFSET和FETCH子句來限制輸出的行數從而達到了分頁效果。相比較SQL Server 2005/2008的ROW_Number函數而言,使用OFFSET和FETCH不僅僅是從語法角度更加簡單,並且擁有了更優的性能(看到很多人下過這個結論,但我測試有所偏差,暫且保留意見)。
MSDN上對於OFFSET和FETCH的詳細描述可以在(http://msdn.microsoft.com/en-us/library/ms188385%28v=SQL.110%29.aspx)找到。
OFFSET和FETCH
這兩個關鍵字在MSDN原型使用方式如代碼1所示。
ORDER BY order_by_expression [ COLLATE collation_name ] [ ASC | DESC ] [ ,...n ] [ <offset_fetch> ] <offset_fetch> ::= { OFFSET { integer_constant | offset_row_count_expression } { ROW | ROWS } [ FETCH { FIRST | NEXT } {integer_constant | fetch_row_count_expression } { ROW | ROWS } ONLY ] }
代碼1.OFFSET和FETCH在MSDN的原型
可以看到,OFFSET使用起來很簡單,首先在OFFSET之后指定從哪條記錄開始取。其中,取值的數可以是常量也可以是變量或者表達式。而Row和ROWS在這里是一個意思。
然后通過FETCH關鍵字指定取多少條記錄。其中,FIRST和NEXT是同義詞,和前面的ROW和ROWS一樣,它們可以互相替換。同樣,這里取的記錄條數也可以是常量或者變量表達式。
下面通過一個例子來看OFFSET和FETCH的簡單用法。首先創建測試數據,這里我就偷懶了,使用我上篇文章的測試數據,創建表后插入100萬條測試數據,這個表非常簡單,一個自增的id字段和一個int類型的data字段,創建表的語句我就不貼了,插入測試數據的代碼如圖1所示。
圖1.插入測試數據
下面,我要取第500000到500100的數據,如圖2所示。
圖2.取50萬到500100之間的數據
可以看到,使用OFFSET和FETCH關鍵字使分頁變得如此簡單。
OFFSET…FETCH分頁對性能的提升
OFFSET和FETCH語句不僅僅是語法糖,還能帶來分頁效率上的提升。下面我們通過一個例子進行比較SQL Server 2012和SQL Server 2005/2008不同分頁方式的分頁效率。我們同樣取50萬到500100之間的數據,性能對比如圖3所示。
圖3.SQL Server 2012分頁和SQL Server 05/08之間分頁效率對比
但是,查詢計划中我看到SQL Server2012中FETCH..NEXT卻十分損耗性能。這和前面的測試結果嚴重不符,如圖4所示。
圖4.兩種方式的執行計划
通過對比掃描聚集索引這步,我發現對於估計執行行數存在嚴重偏差,如圖5所示。
圖5.存在偏差的執行計划
上圖中,第一張圖片是使用OFFSET…FETCH進行分頁的。估計行數居然占到了500100,嚴重不符。這令我十分費解,暫時還沒有找出原因,求各路大神指導….
總結
SQL Server 2012帶來的分頁效果十分強大,使得大大簡化在SQL Server下的分頁。對於性能的影響,由於出現了上述執行計划的偏差,暫且不下結論。待日后研究有了進展再來補上。