詳解SQL Server中SCAN和SEEK的區別
SQL SERVER 使用掃描(scan)和查找(seek)這兩種算法從數據表和索引中讀取數據。這兩種算法構成了查詢的基礎,幾乎無處不在。Scan 會掃描并且返回整個表或整個索引。 而 seek 則更有效率,根據謂詞(predicate),只返索引內的一個或多個范圍內的數據。下面將以如下的查詢語句作為例子來分析 scan 和 seek:
select OrderDate from Orders where OrderKey = 2
Scan
使用 Scan 的方式,SQL Server 會去讀取 Orders 表中的每一行數據,讀取的時候評估是否滿足謂詞 “where order=2”。如果滿足(數據行符合條件),則返回該行。這個例子里,我們將這個謂詞稱作“residual predicate”。為了得到最優的性能,SQL 會盡可能地在掃描中使用“residual predicate”。但如果 residual predicate 的開銷過于昂貴,SQL Server 可能會使用單獨的“filter iterator”. “residual predicate”以 where 關鍵字的形式出現在文本格式的 plan 中。對 XML 格式的 plan,則是
下面這個掃描的文本格式的 plan 的結果:
–Table Scan (OBJECT:([ORDERS]), WHERE:([ORDERKEY]=(2)))
下圖說明了掃描的方式:
無論數據行是否滿足條件,掃描的讀取方式都會訪問表中的每一個數據,所以 scan 的成本和表的數據總量是成比例的。 因此,如果表很小或者表內的大多數數據多滿足謂詞,scan 是一種有效率的讀取方式。然而如果表很大或者絕大多數的數據并不滿足謂詞, 那么這種方式會讓我們訪問到太多不需要的數據頁面,并執行更多的額外的 IO 操作。
Seek
繼續以上面的查詢為例子,如果在 orderkey 列上有一個索引,那么 seek 可能會是一個好的選擇。使用 seek 的訪問方式,SQL Server 會使用索引直接導向到滿足謂詞條件的數據行。 這個例子里,我們將這個謂詞稱為“seek predicate”。 大多數情況下,SQL Server 不必將“seek predicate”重新評估為“residual predicate”。 索引會保證“seek”只返回符合條件的數據行。“seek predicate”以 seek 關鍵字的形式出現在文本格式的 plan 中。 對于 xml 格式的 plan,則以
下面是使用 seek 的文本格式的 plan 的結果:
–Index Seek (OBJECT:([ORDERS].[OKEY_IDX]), SEEK:([ORDERKEY]=(2)) ORDERED FORWARD)
使用 seek 時,SQL Server 只會直接訪問到滿足條件的數據行和數據頁,因此它的成本只跟滿足條件的數據行的及其相應的數據頁面數量成比例, 和基表的數據量完全沒有關系。因此,如果 對于一個選擇性很高(通過這個謂詞,可以篩選掉表中的大部分數據)的謂詞條件,seek 是非常高效的。
下面的表格列出了 seek 和 scan 這兩種查找方式和堆表,聚簇索引和非聚簇索引的各種組合:
Scan | Seek | |
Heap | Table Scan | |
Clustered Index | Clustered Index Scan | Clustered Index Seek |
Non-Clustered Index | Index Scan | Index Seek |
來自: blogs.msdn.com