SQL Server-聚焦ROW_NUMBER VS TOP N性能
前言
抱歉各位,從八月份開始一直在著手寫EntityFramework 6.x和EntityFramework Core 2.0的書籍寫作,所以最近一直遺漏了對博客的管理,後面會著手於寫SQL Server、EntityFramework Core和.NET Core方面的博客。我們知道如果需要查詢前N行數據,除了可以利用TOP N進行查詢外,同樣也可以利用ROW_NUMBER來達到同樣的效果,那麽二者使用哪個性能會更好呢?下面我們來比較下。
ROW_NUMBER VS TOP N
我們利用AdventureWorks2012示例庫中的Production.Product表來進行演示,如下:
DBCC DROPCLEANBUFFERS() DBCC FREEPROCCACHE() GO --ROW_NUMBER QUERY SELECT ProductID FROM ( SELECT ProductID, ROW_NUMBER() OVER (ORDER BY ProductID) AS RN FROM Production.Product ) AS T WHERE T.RN <= 100 GO -- TOP N QUERY SELECT TOP 100 ProductID FROM Production.ProductORDER BY ProductID GO
如上圖所知,對於這兩個查詢計劃的成本是一樣的,都為50%。 如果我們要檢查在兩個聚集索引掃描操作符中讀取的估計行數,那麽我們會註意到兩者都顯示相同的值,即100。可以說聚集索引掃描的估計和實際行數是相同的都是100,如下。
是不是就以此說明二者性能是一樣的呢?稍等片刻,接下來我們將查詢基數再設置大一點看看,比如1000而不再是100,如下:
DBCC DROPCLEANBUFFERS() DBCC FREEPROCCACHE() GO SET STATISTICS IO ON SET STATISTICS TIME ON --ROW_NUMBER QUERYSELECT ProductID FROM ( SELECT ProductID, ROW_NUMBER() OVER (ORDER BY ProductID) AS RN FROM Production.Product ) AS T WHERE T.RN <= 1000 GO -- TOP N QUERY SELECT TOP 1000 ProductID FROM Production.Product ORDER BY ProductID GO
從如上截圖可以看出,使用ROW_NUMBER進行查詢的速度要明顯快於TOP N,即29%和71%。 但是,我們還需要在等一下,因為我們在這裏看到的成本只是估計成本。 如果操作的估算不準確,那麽查詢計劃估算成本也將不準確。 接下來我們檢查兩個計劃中的聚集索引掃描的屬性:
我們可以看到,使用ROW_NUMBER查詢的估計行數為100,而實際數量為504,查詢計劃的估計成本是基於估計的行數所計算得來,即100。我們還是不能夠相信估計的計劃成本。 我們再來看看統計數據:
經過上面的統計,我們可以根據統計數據而做出最終決定,而不是比較執行計劃的估計成本。TOP N的查詢性能優於ROW_NUMBER。
總結
從上比較TOP N和ROW_NUMBER的查詢得知,查詢計劃所得到的成本並不是判斷性能的最終依據,只是基礎性的判斷,我們最終還得集合IO和TIME等來綜合判斷性能差異。
SQL Server-聚焦ROW_NUMBER VS TOP N性能