簡體   English   中英

SQL - 使用CTE並有效地選擇特定row_number()的行

[英]SQL - Using CTE and effectively select rows at a specific row_number()

在這種情況下,CTE中需要SELECT TOP(微觀優化,我知道......)。

DECLARE @pageSize INT, @currentPage INT, @top INT
SET @pageSize = 10
SET @currentPage = 150
SET @top = @pageSize * @currentPage + @pageSize

WITH t AS
(
    SELECT TOP(***@top***) ID, name
    ROW_NUMBER() OVER (ORDER BY ID) AS _row,
    FROM dbo.User
)
SELECT TOP(@pageSize) *
FROM t
WHERE t._row > (@top-@pageSize)
ORDER BY t.ID

以上內容以特定順序從行號列(起始號)返回10(@pageSize)行(@ top- @ pageSize)。 CTE語句是否知道CTE之外的“SELECT TOP”和CTE之外的WHERE子句將會出現,因此CTE永遠不會以特定順序返回比所需更多的行?

基本上只是談論ROW_NUMBER函數,它不計算未返回行的行號(如果我有數百萬行...),如果我要在CTE中選擇前100,那么row_number仍然是計算所選表格中的所有百萬行?

我在CTE語句中嘗試使用和不使用“SELECT TOP(@top)”,在一個運行10.000次的循環中,沒有看到時間使用的任何差異。 雖然,目前我的表中只有38.000行。

編輯:結果如下:

    WITH t AS
(
    **DO A TOP() WITH AN ORDER BY IN THE CTE**
    SELECT TOP(@top) ID, name 
    ROW_NUMBER() OVER (ORDER BY ID) AS _row,
    FROM dbo.User
    ORDER BY ID
)
SELECT TOP(@pageSize) * 
**SELECTING TOP N FROM THE CTE, WHERE ROW-NUMBER IS ... DUE TO THE CTE IS IN ORDER ALREADY**
FROM t
WHERE t._row > (@top-@pageSize)

如果我將它們“向后”排序,選擇CTE的“底部@pageSize”,這可能會更有效率,這將省略where子句......但如果實際上更快,則需要進行一些測試......

不鼓勵使用沒有order bytop 無法保證您將獲得所需的行,因此您不應包含top 或者,您應該order by id列出order by id ,如果這是您想要的訂單。

top的用戶不會影響row_number()計算,因為該計算將在應用top之前完成。 您可以想象在那里有另一個窗口函數,例如sum() over ()以了解top通常不能在row_number()之前應用,並找到安全的環境將是艱苦的工作。

如果您在ID上有支持索引,則不必讀取和枚舉整個表。 SQL Server必須讀取表格,包括您想要的頁面。 因此,如果您想要第1頁(第11行到第20行),則查詢將只獲取20行。 即使您沒有在CTE中使用頂部也是如此。

用於測試一些數據的表:

create table dbo.[User]
(
  ID int identity primary key,
  Name nvarchar(128)
)

go

insert into dbo.[User](Name)
select top(1000) Name
from sys.all_objects

沒有冗余頂部表達式的查詢。

DECLARE @pageSize INT, @currentPage INT, @top INT;
SET @pageSize = 10;
SET @currentPage = 1;
SET @top = @pageSize * @currentPage + @pageSize;
with C as
(
  select U.ID,
         U.Name,
         row_number() over(order by U.ID) as rn
  from dbo.[User] as U
)
select C.ID,
       C.Name
from C
where C.rn > @pageSize * @currentPage and 
      C.rn <= @pageSize * (@currentPage + 1);

這將為您提供如下查詢計划:

在此輸入圖像描述

每個運算符的數量是實際獲取的行數。 聚簇索引掃描讀取按ID排序的20行。 Segment和Sequence Project枚舉行。 Top是運算符,用於確保提取的行數不超過20行。 過濾器刪除行1到10並讓行11到20通過。

如果我們改為嘗試獲取第5頁( @currentPage = 5以獲取第51行到第60行),該計划將如下所示:

在此輸入圖像描述

頂級運算符確保僅從聚簇索引中讀取60行,並且篩選器篩選出前50行以返回最后10行。

使用帶有額外頂部表達式的上一個查詢將不會添加任何有價值的內容。 只有一個額外的冗余頂級操作員

在此輸入圖像描述

理解查詢計划中發生的事情的關鍵是要知道執行是從左到右完成的,每次要求一行。 這就是頂級操作符在返回足夠的行時如何停止聚簇索引掃描。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM