當我有 6 個核心並且他們進行表掃描並隨後合併時,每個核心是否都會掃描整個表?
我記得我曾經在一張表上有一個缺失的索引,一個查詢需要很長時間。在執行計劃中,我看到完成了表掃描和合併。來自 IO 的統計數據顯示,每個核心都進行了一次表掃描,或者更好的是我得到了 6 次表掃描。現在我想知道是每個核心都進行全掃描,還是每個核心大致進行 1/6 表掃描?我肯定知道,如果我有一個適當的索引,我要麼只進行一次搜尋,要麼將它拆分為每個核心。
我希望你能理解我在這裡的意思,不幸的是我無法提供任何資訊,因為這個問題剛剛出現,我的問題在幾年前就已經解決了。
坦率地說,我不確定您所說的“合併完成”是什麼意思。你說的是合併連接嗎?也許您的意思是並行運算符?至少我可以回答有關並行表掃描的問題。
來自 IO 的統計數據顯示,每個核心都進行了一次表掃描,或者更好的是我得到了 6 次表掃描。
我假設您的意思是您
SET STATISTICS IO ON
在執行查詢之前執行,並且部分輸出包括如下內容:表’your_table’。掃描計數 6,…
標籤“掃描計數”有點誤導。您不應得出結論,如果
STATISTICS IO
報告了 6 次掃描,則表中的所有行都被掃描了 6 次。考慮以下對名為 的堆表的簡單範例查詢heap_table
:SELECT TOP 1 * FROM heap_table OPTION (MAXDOP 1);
對於該查詢,
STATISTICS IO
應該報告掃描計數為 1,對嗎?但是 SQL Server 顯然不需要讀取表中的所有行。查看掃描計數標籤的定義也很有幫助:在任何方向達到葉級別後開始的搜尋/掃描次數,以檢索所有值以建構輸出的最終數據集。
…
當 N 是使用索引鍵定位鍵值後,在葉級別向左側或右側開始的不同搜尋/掃描次數時,掃描計數為 N。
因此,如果您的查詢進行了並行掃描,我希望看到掃描計數至少為 6,但這並不一定意味著表中的所有行都被讀取了六次。你怎麼知道這些行是如何分佈在你的 CPU 核心中的?
最簡單的方法是只看一個實際的執行計劃。如果您查看並行掃描的詳細資訊,SQL Server 將顯示每個 CPU 執行緒處理了多少行。下面是從 Paul White 的文章Parallel Execution Plans – Branches and Threads中藉用的圖片:
正如你所說,你幾年前遇到過這個查詢,所以這種方法對你沒有幫助。相反,我們需要查看 SQL Server 可用於並行計劃處理的技術。Craig Freedman 有一系列關於這個主題的部落格文章。來自並行掃描文章:
並行掃描如何工作?
組成並行掃描的執行緒一起工作以掃描表中的所有行。特定執行緒沒有先驗分配或行或頁面。相反,儲存引擎動態地將頁面分發給執行緒。並行頁面供應商協調對錶格頁面的訪問。並行頁面供應商確保每個頁面都分配給一個執行緒,因此只處理一次。
好吧,你有它。就像我之前所說的,您可以通過執行帶有並行掃描的查詢並在實際執行計劃中檢查並行掃描運算符的詳細資訊來輕鬆測試這一點。
對於另一種看待它的方式,請嘗試考慮一個場景,在該場景中,SQL Server 對每個核心進行全表掃描是有益的。
假設您碰巧有一個
UNION ALL
查詢引用了您的表六次。原則上,SQL Server 可以獨立地用一個核進行每次表掃描,並在最後合併結果。但是,SQL Server 不會這樣做,因為它不會進行管道並行。即使可以,我個人也想不出在這裡這樣做的好處,除了避免一些與並行性相關的成本。您可以閱讀有關並行執行的廣播類型的資訊,並想知道在這種情況下 SQL Server 是否可以對一個表進行六次完整掃描,每個核心一次。對於交換的廣播類型,SQL Server 將所有行發送到所有消費者執行緒。但是,這可以通過對錶進行串列掃描,然後進行分佈式流類型的並行交換來完成。事實上,這就是您在雜湊連接範例中看到的內容。我真的想不出並行進行掃描的好處,尤其是當廣播類型僅用於相對較小的表時。
我認為可能發生這種情況的一種情況是,如果您有一個並行嵌套循環連接,其中包含一個包含 6 行的外部表,並且在連接的內側有一個表掃描。在這種情況下,我相信表掃描將由獨立的串列執行緒完成,因此您可以有效地讓每個核心進行自己的表掃描。當然,這樣的查詢可能性能很差,不是目標,尤其是當外部表超過六行時。