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,則是<predicate>標記的形式。

下面這個掃描的文本格式的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,則以<seekpredicates>標記出現。

下面是使用seek的文本格式的plan的結果:

|--Index Seek(OBJECT:([ORDERS].[OKEY_IDX]), SEEK:([ORDERKEY]=(2)) ORDERED FORWARD)

使用seek時,SQL Server只會直接訪問到滿足條件的數據行和數據頁,因此它的成本只跟滿足條件的數據行的及其相應的數據頁面數量成比例, 和基表的數據量完全沒有關係。因此,如果對於一個選擇性很高(通過這個謂詞,可以篩選掉表中的大部分數據)的謂詞條件,seek是非常高效的。

下面的表格列出了seekscan這兩種查找方式和堆表,聚簇索引和非聚簇索引的各種組合:

  Scan Seek
Heap Table Scan  
Clustered Index Clustered Index Scan Clustered Index Seek
Non-Clustered Index Index Scan Index Seek
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章