天天看點

SQL Server-聚焦IN VS EXISTS VS JOIN性能分析(十九)前言

本節我們開始講講這一系列性能比較的終極篇IN VS EXISTS VS JOIN的性能分析,前面系列有人一直在說場景不夠,這裡我們結合查詢索引列、非索引列、查詢小表、查詢大表來綜合分析,簡短的内容,深入的了解,Always to review the basics。

我們繼續建立測試表,如下

建立三個表即t_outer、t_inner、t_smaler同時将三個表中的列val1建立索引而對t_smaller表中的val2未建立索引,下面我們開始插入測試資料

對t_inner和t_outer分别插入10萬條随機資料,然後去取t_outer表中最後100條資料插入到表t_smaller中

表以及測試資料建立完畢,下面我們開始一個一個分析。

SQL Server-聚焦IN VS EXISTS VS JOIN性能分析(十九)前言

我們将上述查詢計劃示意圖過程簡短描述成如下:

SQL Server-聚焦IN VS EXISTS VS JOIN性能分析(十九)前言

整個查詢耗費時間如下:

SQL Server-聚焦IN VS EXISTS VS JOIN性能分析(十九)前言

此時整個查詢時間耗費70毫秒,對于10萬條資料來說算是非常快的了,因為此時我們在t_inner表和t_outer表上的列val1都建立了索引,是以此時選擇Stream Aggregate來進行過濾去除對于t_outer表上的val1中對應的t_inner表上的val1的重複值。到底是怎麼去除重複的呢?它會記錄重複的最後一個值,當再有值被找到,此時将無法通過。上述之是以查詢非常快的原因在于輸入行已經提前進行了預排序。最後得到的兩個表的結果集進行Merge Join,進行Merge Join時,它會初始化一個變量并将指針指向加入的兩個列的最小值,然後傳回兩個表結果集中比對到的值,然後将指針指向下一個兩個索引列中的存在的值,否則跳過不比對的值,一直到完成,當進行如下查詢時和上述查詢計劃是一緻的。

我們通過如下查詢來分析EXISTS

SQL Server-聚焦IN VS EXISTS VS JOIN性能分析(十九)前言
SQL Server-聚焦IN VS EXISTS VS JOIN性能分析(十九)前言

上述我們能夠很清楚的知道EXISTS查詢計劃和IN是一緻的,信不信由你,當下次面試再問二者性能的問題時,可千萬别說EXISTS性能高于IN,這是錯誤的,上述我們已經分析得出其實是一樣的。如果你仍是覺得EXISTS性能高于IN,請用事實證明。上述我們一直示範的是查詢索引列val1,那要是在非索引列val2上查詢會怎樣呢。

我們再來分析下查詢計劃

SQL Server-聚焦IN VS EXISTS VS JOIN性能分析(十九)前言
SQL Server-聚焦IN VS EXISTS VS JOIN性能分析(十九)前言

我們重點看看Hash Match(Left Semi Join),此時對t_outer表上的值建立哈希表,然後t_inner表中每一行值來探測該哈希表,接着通過Left Semi Join來比對值,如果比對到值,此時比對到的值會立即從哈希表中移除,最終哈希表将逐漸縮小。接着我們再來看EXISTS。

SQL Server-聚焦IN VS EXISTS VS JOIN性能分析(十九)前言
SQL Server-聚焦IN VS EXISTS VS JOIN性能分析(十九)前言

此時我們看到無論是查詢索引列還是非索引列EXISTS和IN在查詢計劃和耗費時間幾乎完全是一緻的,到這裡我們針對讨論的是大表10萬條資料,下面我們會讨論在小表t_smaller中有關二者的查詢。接下來我們看看利用JOIN在索引列上進行查詢。

SQL Server-聚焦IN VS EXISTS VS JOIN性能分析(十九)前言
SQL Server-聚焦IN VS EXISTS VS JOIN性能分析(十九)前言

我們看到查詢耗費時間和查詢計劃都和EXISTS、IN有不同,我們再來看看執行的順序。

SQL Server-聚焦IN VS EXISTS VS JOIN性能分析(十九)前言

與上述不同的是JOIN在兩個表聯合之前首先進行了Hash Match(Aggregate),也就是說和EXISTS、IN不同之處在于重複值的處理,對于EXISTS、IN來說直接将兩個表進行聯合然後通過LEFT Semi Join來進行過濾重複值,在此通過哈希比對中的聚合來過濾去除重複值val2,Hash Match(Aggregare)建立了一個唯一的哈希表,是以很容易來過濾重複值,因為有重複值過來時唯一哈希表能夠探測到會産生值沖突,此時重複值都不會進入哈希表中。查詢引擎通過哈希表來探測t_outer中的值,最終傳回比對的值。普遍想法是JOIN性能比EXISTS、IN性能要好,上述我們在查詢非索引列時其查詢開銷和耗費時間卻比EXISTS、IN要高,是以相對來說JOIN對于查詢非索引列時其性能是比較低效的。接下來我們繼續來看看查詢小表t_smaller的情況。

我們查詢小表看看關于IN的查詢情況是怎樣的呢

SQL Server-聚焦IN VS EXISTS VS JOIN性能分析(十九)前言
SQL Server-聚焦IN VS EXISTS VS JOIN性能分析(十九)前言

因為資料隻有100條的小表其查詢耗費時間當然非常少且查詢速度非常快,我們重點看看其查詢計劃。此時合并結果集時不再是Merge Join代替的是周遊整個索引,它會掃描整個t_smaller表來過濾重複值,當然僅僅隻是查找在t_outer表上建立的索引列val1且是通過索引查找的方式。資料量小是以即使是周遊整個索引也是非常快的。在EXISTS和JOIN中其執行計劃結果和上述一緻,下面我們再來看看查詢非索引列的情況。

SQL Server-聚焦IN VS EXISTS VS JOIN性能分析(十九)前言
SQL Server-聚焦IN VS EXISTS VS JOIN性能分析(十九)前言

此時我們看到查詢小表上非索引列val2和大表上的非索引列val2執行計劃幾乎是一樣的,有一點不同的是在大表中建立哈希表是在外部查詢表中,在這裡卻是在子查詢表中建立哈希表,這就是查詢引擎高明的地方,資料少時在小表上建立哈希表一來在哈希表中存儲的資料少即占用記憶體少,二來當比對到值時就縮減哈希表的大小。我們再來看看JOIN的情況。

SQL Server-聚焦IN VS EXISTS VS JOIN性能分析(十九)前言
SQL Server-聚焦IN VS EXISTS VS JOIN性能分析(十九)前言

因為資料量小是以耗費時間短,這個我們可以忽略不看,我們還是看看查詢計劃情況,此時利用Distinct Sort來消除重複的資料而不是利用哈希表,它會一次次的重建,可想而知性能的低下。分析到這裡為止,我們看到在SQL Server中其實在有些情況下IN、EXISTS的查詢性能是高于JOIN的。還不相信嗎,我們再來看一個例子。

SQL Server-聚焦IN VS EXISTS VS JOIN性能分析(十九)前言
SQL Server-聚焦IN VS EXISTS VS JOIN性能分析(十九)前言

IN VS EXISTS VS JOIN性能分析結論:在查詢非索引列時,利用JOIN查詢性能低下,因為利用EXISTS和IN會直接利用半聯接來比對哈希表,而JOIN需要先進行哈希聚合之後再進行完全JOIN,換句話說,EXISTS和IN隻需一步操作就完成,而JOIN需要兩步操作來完成,當然對于有索引的前提下,資料量巨大的話,利用JOIN其性能同樣也是非常高效的。而IN和EXISTS的性能是一樣的,至于為何推薦用EXISTS的原因在于基于EXISTS是三值邏輯,而IN是兩值邏輯,利用EXISTS來查詢比IN更加靈活,安全、保險,而且大多數情況下利用IN來查詢都可以利用EXISTS來代替查詢。

本節我們讨論了IN VS EXISTS VS JOIN的性能比較,至此關于所有IN/NOT IN VS EXISTS/NOT EXISTS VS JOIN/LEFT JOIN..IS NULL的性能分析到此告一段落,接下來我們将會講述Stream Aggregate VS Hash Match Aggregate,敬請期待,簡短的内容,深入的了解,我們下節再會。