什麼時候沒有索引比擁有聚集索引更快?
我執行了相同的查詢,其中涉及連接兩個表 A 和 B,而 B 根本沒有索引,然後在用於連接它的 ID 列上添加了一個 PK 聚集索引。沒有索引時經過的時間實際上更快?
無索引結果:
Table 'Table_A'. Scan count 5, logical reads 1764, ... Table 'Table_B'. Scan count 10, logical reads 16976, ... SQL Server Execution Times: CPU time = 859 ms, elapsed time = 269 ms.
將 PK 聚集索引添加到 Table_B
Table 'Table_A'. Scan count 1, logical reads 445, ... Table 'Table_B'. Scan count 2, logical reads 17026, ... SQL Server Execution Times: CPU time = 1046 ms, elapsed time = 1053 ms.
雖然 Table_B 沒有索引時 IO 數更高,但它怎麼可能更快呢?有索引的表怎麼會比沒有的慢?有什麼合乎邏輯的解釋嗎?
查看兩個查詢的經過時間與 CPU 時間的比率,我們可以看到“無索引”查詢受益於並行性 - CPU 時間大約是經過時間的 3 倍。
將聚集索引添加到 Table_B 後,您將獲得該執行計劃的串列版本(CPU 時間和執行時間大致相等)。或者可能是一個完全不同的串列執行計劃,但是在兩個查詢中 Table_B 的掃描頻率是 Table_A 的兩倍,這讓我認為總體計劃形狀可能是相同的。
有了聚集索引,優化器可能會推斷它可以利用聚集索引的排序特性,因此不需要產生並行性成本。
在這種情況下,總體而言,優化器似乎做出了一個不錯的決定:第二個查詢使用更少的 CPU 核心,讀取更少的數據頁,但代價是經過的時間略有增加
如果您編輯您的問題以包含更多詳細資訊(實際執行計劃、表定義、範例數據),那麼有人可能能夠提供更具體針對您的情況的答案。
正如Josh Darnell 先生詳細回答的那樣,優化器做出的決定以及由於預先排序的數據而導致的並行性細節,我想在答案中補充一點,我們主要依靠邏輯讀取來衡量性能,而不是時間,因為時間會根據伺服器負載、網路、磁碟等許多因素而變化很大(您可以通過多次執行相同的查詢並檢查持續時間來測試它),而無論您執行多少次,邏輯讀取都將保持一致除了已執行維護作業或已更新統計資訊或更改索引的唯一例外情況。
話雖如此,如果您注意到第一個查詢和第二個查詢中經過的時間之間的差異,它非常小,而邏輯讀取要少 5 倍(掃描計數)。我知道這聽起來可能太多了,因為這裡的數字非常小,但是如果我們在更大的範圍內使用它,優化器在記憶體中為滿足查詢而帶來的數據將比使用聚集索引的數據少 5 倍。 -聚集索引。
這就是它的最佳實踐是在幾乎所有場景中都使用聚集索引的原因,除非它是一個僅進行插入並且很少執行選擇查詢的臨時數據庫。