TOPN 如何影響使用 group by 的查詢?
我有一個如下所示的查詢:
Select t1.field1, t2.field2, sum(t1.field3) From t1 inner join t2 on t1.id = t2.id Group by t1.field1, t2.field2
它被簡化了,通常它上面還有一些連接和屬性。我現在的問題是,將 TOP N 子句添加到查詢而不是在 N 行返回到我的 C# 程式碼後停止查詢的影響有多大。
我知道,添加該子句對伺服器來說更好,但我對粗略估計該子句的影響感興趣。我的猜測是,因為我有一個聚合,伺服器無論如何都必須處理所有行,因此影響不是那麼高。
編輯:C# Snippet 我們如何停止執行
var cmd = new SqlCommand(); cmd.CommandText = sqlStatement; cmd.Connection = connectionString; SqlDataReader dr; dr = cmd.ExecuteReader(); while (dr.HasRows) { while (dr.Read()) { MyDataRow newRow = new MyDataRowDataRow(); newRow.Parse(dr); //Parse the value from datarow to our format result.Add(newRow); if (topN.HasValue) { if (result.Count >= topN.Value) { break; //stop reading! } } } dr.NextResult(); }
我的猜測是,因為我有一個聚合,伺服器無論如何都必須處理所有行,因此影響不是那麼高。
從 SQL Server 的角度來看,這取決於。以下是它所依賴的內容以及原因的概述:
行目標
添加頂級
TOP (n)
子句(帶或不帶ORDER BY
)具有與指定查詢提示相同的行目標效果。FAST (n)
行目標使優化器根據快速返回n行來估計計劃成本。因此,小行目標傾向於使用非阻塞(流水線)操作符(如(無排序)合併或嵌套循環連接)和半阻塞(每組)操作符(如流聚合)串列執行,而不是完全阻塞操作符(如排序和急切雜湊)清楚的。
如果預計建構輸入很小,並且預計建構輸入不會重新綁定太多(或在全部)。
流水線執行
在查詢邏輯允許並且存在合適索引的情況下,優化器很可能能夠找到完全流水線(或者可能是半阻塞)的執行計劃。每組阻塞的半阻塞計劃可能很好,只要組很小。
即使使用最佳索引,在某些情況下,也可能需要使用正確的語法來表達查詢,也許還需要使用各種查詢和表提示,以獲得盡可能多的流水線執行計劃。除了最簡單的情況外,在所有情況下都很難實現。
流水線/半阻塞計劃意味著
SqlDataReader.Read()
可以以最小的延遲獲取第一行和後續行。本質上,C# 程式碼和 SQL Server 執行引擎都是流式行。在這種情況下,指定TOP (n)
將產生最大的不同。預設策略
如果
TOP (n)
未指定,查詢優化器的目標是查詢預期生成的*全部潛在行集的**總執行時間。*例如,優化目標的這種變化傾向於支持並行性、完全阻塞排序和急切雜湊聚合,以及部分阻塞雜湊連接。這通常會比執行流水線/半阻塞計劃(如果可用)到最終結論快得多。當一個或多個阻塞操作符出現在一個計劃中時,第一行的時間可能是潛在總執行時間的相當大的一部分。這意味著第一次
SqlDataReader.Read()
呼叫將阻塞很長時間。在這種情況下,在客戶端接收到 n 行後停止 DataReader 將對經過的時間產生相對較小的影響,因為在第一行可用之前,大部分 SQL Server 工作已經完成。結論
因此,增加多少效果
TOP (n)
至少取決於:
- 有一個流水線執行計劃解決方案(即使在原則上)
- 合適的訪問方法(索引)
- 查詢語法和優化器功能/限制
- 查詢開發人員的技能水平和經驗
例子
使用ContosoRetailDW 範例數據集,其中表
FactOnlineSales
有 12,627,600 行。基於問題中模板的查詢是:SELECT FOS.ProductKey, DS.StoreKey, SUM(FOS.SalesAmount) FROM dbo.DimStore AS DS JOIN dbo.FactOnlineSales AS FOS ON DS.StoreKey = FOS.StoreKey GROUP BY FOS.ProductKey, DS.StoreKey ORDER BY FOS.ProductKey, DS.StoreKey;
添加有用的索引:
CREATE INDEX i ON dbo.FactOnlineSales (ProductKey, StoreKey) INCLUDE (SalesAmount);
執行計劃是:
這執行1650ms。注意排序和散列操作。
與 TOP (n)
任意選擇 n = 50,查詢現在是:
SELECT TOP (50) FOS.ProductKey, DS.StoreKey, SUM(FOS.SalesAmount) FROM dbo.DimStore AS DS JOIN dbo.FactOnlineSales AS FOS ON DS.StoreKey = FOS.StoreKey GROUP BY FOS.ProductKey, DS.StoreKey ORDER BY FOS.ProductKey, DS.StoreKey;
和執行計劃:
使用流水線迭代器和每組半阻塞流聚合(而不是阻塞急切雜湊)執行 57 毫秒。
相關問題:如何(以及為什麼)
TOP
影響執行計劃?