1. 程式人生 > >SQL Server-聚焦ROW_NUMBER VS TOP N性能

SQL Server-聚焦ROW_NUMBER VS TOP N性能

性能 計算 order rop tid serve color sql buffer

原文: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.Product
ORDER BY ProductID GO

技術分享圖片

如上圖所知,對於這兩個查詢計劃的成本是一樣的,都為50%。 如果我們要檢查在兩個聚集索引掃描操作符中讀取的估計行數,那麽我們會註意到兩者都顯示相同的值,即100。可以說聚集索引掃描的估計和實際行數是相同的都是100,如下。

技術分享圖片

是不是就以此說明二者性能是一樣的呢?稍等片刻,接下來我們將查詢基數再設置大一點看看,比如1000而不再是100,如下:

DBCC DROPCLEANBUFFERS()
DBCC FREEPROCCACHE()
GO
SET STATISTICS IO ON
SET STATISTICS TIME ON
--ROW_NUMBER QUERY
SELECT 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性能