sqlserver 執行計劃

想複雜的事情簡單說,在看執行計劃的其他文章的時候,發現直接上很複雜的DDL腳本來講解,這樣子可能打開就沒有興趣往下看了。所以這裏用了一個最簡單的select語句進行說明引新入門。

打開

注意這三個【L型圖標】,可以把鼠標移動到按鈕上方可以顯示【解釋文字】。

圖中從左到右分別爲【顯示估計的執行計劃】【包括實際的執行計劃】【包括實時查詢統計信息】。

【顯示估計的執行計劃】是執行某個DDL的估計值。

【包括實際的執行計劃】【包括實時查詢統計信息】都是執行實際的值,所以你選擇後,它會在下次執行後出執行結果。

結果分析

這是一個簡單的查詢,鼠標點擊圖片中的圖片或線上都有驚喜(大量細節信息展示)。執行計劃可以通過“另存”操作將某一次結果保留下來,方便與日後進行結果對比。

除了圖標外,線的粗細代表涉及到的數據量的大小,越粗代表數據量越大。

執行計劃元素列表如下:

   
Select (Result) Sort Spool
Clustered Index Scan Key Lookup Eager Spool
NonClustered Index Scan Compute Scalar Stream Aggregate
Clustered Index Seek Constant Scan Distribute Streams
NonClustered Index Seek Table Scan Repartition Streams
Hash Match RID Lookup Gather Streams
Nested Loops Filter Bitmap
Merge Join Lazy Spool Split

執行計劃元素列表解釋請參考:

https://docs.microsoft.com/en-us/previous-versions/sql/sql-server-2008-r2/ms175913(v=sql.105)

https://lvraikkonen.github.io/2017/06/02/%E7%9C%8B%E6%87%82SQL%20Server%E6%89%A7%E8%A1%8C%E8%AE%A1%E5%88%92/

結果細節圖

 

其中,第三個圖中的屬性Ordered是與order by相關。如下面兩個腳本:

select * from vvtest order by id;
select * from vvtest

兩個執行計劃的結果如下:

 

所謂數據訪問就是直接訪問數據,可以是訪問一個表也可以是訪問一個索引。

通常有兩種方法:一種是掃描(scan)一種是查找(seek)。

  • scan就是讀取整個結構,可以訪問一個heap或者一個clustered索引或者一個non-clustered索引。
  • seek不會讀取整個結構,他則是更高效地通過索引訪問一行,所以從這個角度來看,查找就只能應用在索引上面了。簡單總結如下表所示:

首先分析最右邊的Table Scan。這是sqlserver 查詢數據的方法。sqlserver 數據查詢方式一共有五種:

1. 【Table Scan】:遍歷整個表,查找所有匹配的記錄行。這個操作將會一行一行的檢查,當然,效率也是最差的。
2. 【Index Scan】:根據索引,從表中過濾出來一部分記錄,再查找所有匹配的記錄行,顯然比第一種方式的查找範圍要小,因此比【Table Scan】要快。
3. 【Index Seek】:根據索引,定位(獲取)記錄的存放位置,然後取得記錄,因此,比起前二種方式會更快。
4. 【Clustered Index Scan】:和【Table Scan】一樣。注意:不要以爲這裏有個Index,就認爲不一樣了。 其實它的意思是說:按聚集索引來逐行掃描每一行記錄,因爲記錄就是按聚集索引來順序存放的。 而【Table Scan】只是說:要掃描的表沒有聚集索引而已,因此這二個操作本質上也是一樣的。
5. 【Clustered Index Seek】:直接根據聚集索引獲取記錄,最快!

所以總體來講,在查詢結果集是相同數量的情況下,查詢速度排序爲5>3>2>4>1。

一般而言,在性化時可以看到執行記錄時是不是【Table Scan】或者【Clustered Index Scan】,如果是,可以通過增加或修改索引類型進行效率上的對比。

Lookup類型

我是真的服氣這麼多名詞解釋。

Bookmark Lookup、RID Lookup、Key Lookup。

Bookmark Lookup和Key Lookup是一個意思,等價。

如果表沒有創建聚集索引則稱爲Bookmark Lookup,如果表中沒有聚集索引但是存在非聚集索引我們稱爲RID Lookup。

爲什麼突然扯了一嘴Lookup呢?因爲Lookup其實就是與執行計劃裏的scan或index相關。如果聚集索引命中就是指Bookmark Lookup——聚集索引命中的時候,很大概率是索引不能帶出select所需的某一部分字段或者是全部字段,所以需要先命中一行,然後把某一行的數據全帶出來。非聚集索引命中就是指RID Lookup。

SQL SERVER如何選擇執行計劃

sqlserver選擇某個執行計劃,執行計劃用某個索引,是這有一個權重判斷的。這個權重在執行前都計算出來了。那怎麼查看呢——通過【索引統計信息】。在執行腳本的過程中,sqlserver會根據這些統計信息,選擇一個它認爲是最合適的方法去執行查詢過程。統計信息可以自動定時更新,在SQL Server中也有個參數來控制這個更新方式。

語法

DBCC SHOW_STATISTICS ("Person.Address", AK_Address_rowguid);

這裏的引號很重要,沒會報錯。

主要有兩個參數:

第一個:是表名或者是索引視圖名(給視圖加的索引)

第二個:索引名、列名、統計信息。

結果屬性介紹

索引前綴集是什麼?索引前綴和前綴索引不是一個東西。

索引前綴是指索引的選擇性——根據索引定義時的字段順序來決定索引是否被命中。如果是索引(a,b,c),命中查詢的時候是查詢條件中有(a) (a,b) (a,b,c)進行命中,但是(b,c)這個查詢條件不會命中該索引。所以索引前綴也叫索引列前綴集。

前綴索引說白了就是對文本的前幾個字符(具體是幾個字符在建立索引時指定)建立索引,這樣建立起來的索引更小,所以查詢更快。

索引統計信息屬性介紹
屬性 介紹 備註
表1 列出了這個索引統計信息的主要信息。 --
Name 統計信息的名稱 語法裏的第二個參數
Updated 上一次更新統計信息的日期和時間。  
Rows 表中的行數。  
Rows Sampled 統計信息的抽樣行數。  
Step

數據可分成多少個組,與第三個表有多少行相對應。

 
Desity 中文翻譯:密度。根據索引列計算不同值的分佈密度。 Calculated as 1 / distinct values for all values in the first key column of the statistics object
Average key Length 所有索引列的平均長度。  
String Index 如果爲“YES”,則統計信息中包含字符串摘要索引,以支持爲 LIKE 條件估算結果集大小。僅適用於 charvarcharnchar 和 nvarcharvarchar(max)nvarchar(max)text 以及 ntext 數據類型的前導列  
Filter Expression 謂詞表達式  
Unfiltered Rows

上面的Filter Expression所操作的數據總行數

爲NULL,代表Filter Expression沒有匹配到具體數據。

 
表2 它列出各種字段組合的選擇性,數據越小表示重複越性越小,當然選擇性也就越高。 --
All density 索引列前綴集的選擇性(包括 EQ_ROWS)。注意:這個值越小就表示選擇性越高。 如果這個值小於0.1,這個索引的選擇性就比較高,反之,則表示選擇性就不高了。
Average Length 索引列前綴集的平均長度。  
Columns 爲其顯示 All density 和 Average length 的索引列前綴的名稱  
表3 數據分佈的直方圖,SQL Server就是靠它預估一些執行步驟的數據量。 --
RANGE_HI_KEY 直方圖的數據最大值  
RANGE_ROWS 每組數據組的估算行數,不包含最大值。  
EQ_ROWS 每組數據組中與最大值數據(RANGE_HI_KEY)相等的行數目 估計值
DISTINCT_RANGE_ROWS 每組數據組中的非重複值的估算數目,不包含最大值。  
AVG_RANGE_ROWS 每組數據組中的重複值的平均數目,不包含最大值,計算公式:RANGE_ROWS / DISTINCT_RANGE_ROWS for DISTINCT_RANGE_ROWS > 0  
     

 

執行計劃詳細屬性介紹

在執行DDL之前,輸入一句set statistics profile on 。顯示一個表格,表格內是比圖上更細節的實際的執行信息。針對這個表的屬性做一個整理解析。

執行計劃屬性
屬性 字段介紹 備註
Rows(重要屬性) 在某個步驟中,實時產生的記錄條數 真實數據
Executes(重要屬性) 某個步驟被執行的次數。 真實數據
StmtTest(重要屬性)

執行步驟的描述

1)  |--Table Scan(OBJECT:([master].[dbo].[vvtest]))

2)  |--Clustered Index Scan(OBJECT:([master].[dbo].[vvtest].[ClusteredIndex-20190531-153224]))

3)select * from vvtest

1和2是加了沒有聚集索引和把id作聚集索引後的對比。3是DDL是執行計劃最外層的腳本執行。2中的加黑部分是在查詢方式是Clustered Index Scan的時候他使用到的索引名稱。

所以這個屬性可以看到使用的索引和實際步驟裏執行的DDL腳本。

StmtId

當前執行語句的單條DDL的編號。

set statistics profile on 
select * from vvtest order by id;——這條就是1
select * from vvtest——這條就是2
NodeId 單條DDL裏的步驟編號。 從1開始,單個執行計劃中箭頭最右邊是1,最左邊(被指的)依次增加,代表單個DDL內的執行順序。
Parent 與該條步驟相關的下一步步驟編號(NodeId)  
PhysicalOp sqlserver 數據查詢方式,包括但是不限於我們上面提到的五種Table Scan…… 只有節點類型Type=PLAN_ROWS 的纔有這個屬性。Type屬性在下方介紹
LogicalOp 關係運算符 只有節點類型Type=PLAN_ROWS 的纔有這個屬性。Type屬性在下方介紹
Argument 被PhysicalOp執行的對象,細節信息,比如說當前被使用到的列名或表名

舉例:

Sort——ORDER BY:([master].[dbo].[vvtest].[id] ASC)

Table Scan ——OBJECT:([master].[dbo].[vvtest])

DefinedValues 將DDL語句進行細化成一個用逗號分隔的列表。  
EstimateRows 估計返回多少行數據 估計值
EstimateIO 估計IO開銷,單位是 估計值
EstimateCPU 估計CPU開銷,計算的是CP佔用率(百分比) 估計值
AvgRowSize 估計本步驟的數據每行平均的字節數,單位是bytes 估計值
TotalSubtreeCost 估計的本步驟和本步驟涉及到所有子步驟的總消耗的佔總的百分比 估計值
OutPutList 這個屬性是一個用逗號分隔的列表。列表裏是本步驟執行的DDL,輸出涉及到對應表的列名。 列名集合
Warnings 用逗號分隔的列表,本步驟DDL會觸發的警告信息。  
Type 節點類型

1)如果是陳述性SQL,那麼Type的值爲SELECT, INSERT, EXECUTE等。

2)如果是執行計劃的子節點(如索引執行的描述),那麼Type的值爲PLAN_ROW

Parallel

並行標誌。

0-本步驟不能並行執行

1-本步驟可以並行執行

 
EstimateExecutions 估計本步驟在總的執行中被執行的次數。

估計值。

有可能在腳本中步驟被執行N次

 

以上屬性的英文版的解釋在:

https://docs.microsoft.com/en-us/sql/t-sql/statements/set-showplan-all-transact-sql?view=sql-server-2017

參考文檔:https://www.cnblogs.com/fish-li/archive/2011/06/06/2073626.html

https://docs.microsoft.com/en-us/sql/t-sql/database-console-commands/dbcc-show-statistics-transact-sql?view=sql-server-2017

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