天天看點

SQL Server-聚焦NOT IN VS NOT EXISTS VS LEFT JOIN...IS NULL性能分析(十八)前言

本節我們來綜合比較NOT IN VS NOT EXISTS VS LEFT JOIN...IS NULL的性能,簡短的内容,深入的了解,Always to review the basics。

我們首先建立測試表

接着我們在兩個表中的列value上建立索引

我們在t_left和t_right表中插入如下測試資料

我們稍微解釋下上述插入的測試資料:

(1)t_left表中插入10萬條資料,其中包含1萬條重複資料。

(2)t_right表中插入100萬條資料,其中包含1萬條重複資料。

(3)t_left表中插入10條t_right表中沒有的資料。

接下來我們一個個來看看其查詢執行計劃。

SQL Server-聚焦NOT IN VS NOT EXISTS VS LEFT JOIN...IS NULL性能分析(十八)前言
SQL Server-聚焦NOT IN VS NOT EXISTS VS LEFT JOIN...IS NULL性能分析(十八)前言

我們重點看看上述圖做了标記的兩個重要的地方,最後傳回結果集時使用了Merge Anti Semi Join也就是說是上述Merge Join和Right Anti Semi Join的結合,可以說這是一種非常高效的方式,事先通過索引來排序然會擷取兩個表的結果集。資料庫通過Merge Join來疊代兩個表的結果集從小值到大值,當然也是通過指針指向二者結果集的目前值然後接着指向下一個值。而Anti Semi Join主要是幹什麼的呢?前面我們講過它是半聯接,此時資料庫引擎隻要比對到t_right表中的值就跳過所有t_left和t_right表其他也同樣比對的同一個值,為什麼會跳過呢? 因為此時Stream Aggregate起到了決定性作用(【關于Stream Aggregate前面簡單了解了下,感覺了解的還是不夠透,寫這篇文章時才算是灰常了解了,後續會專門寫寫Stream Aggregate和Hash Aggregate】)我們知道Stream Aggregate首先需要排序,然後進行分組接着就是聚合,因為我們建立了索引是以就有了排序,接着執行Stream Aggregate進行分組,通過檢視Stream Aggregate如下具體資訊知道。因為對t_right表中的值進行了分組,是以當進行合并右半聯接時,隻取組中第一個,其餘的自然而然就進行跳過,是以這種方式非常高效,通過索引來進行排序,再通過Stream Aggregate進行分組,最後執行Merge Join(Right Anti Semi Join)。最後我們看到查詢僅僅隻耗費了0.315秒。

SQL Server-聚焦NOT IN VS NOT EXISTS VS LEFT JOIN...IS NULL性能分析(十八)前言

我們運作如下查詢

SQL Server-聚焦NOT IN VS NOT EXISTS VS LEFT JOIN...IS NULL性能分析(十八)前言

關于其查詢耗費時間就不再給出了,其實NOT EXISTS和NOT查詢計劃和查詢時間都是一樣的,并沒有任何差別,我們之前在單獨讨論NOT EXISTS和NOT IN時就已經明确說過,二者在查詢列不為NULL的前提下,二者的查詢開銷是一樣的,而将查詢列設定為可NULL時,NOT EXISTS的性能遠高于NOT IN,這裡我們就不過多的讨論了,不明白的童鞋可以看看前面關于二者比較的文章。

SQL Server-聚焦NOT IN VS NOT EXISTS VS LEFT JOIN...IS NULL性能分析(十八)前言
SQL Server-聚焦NOT IN VS NOT EXISTS VS LEFT JOIN...IS NULL性能分析(十八)前言

到這裡我們知道很顯然結果集肯定是一樣的,但是查詢計劃和上述NOT EXISTS、NOT IN有很大的差異,LEFT JOIN...IS NULL首先是使用LEFT JOIN傳回所有資料,其中包括重複的,然後再進行過濾,為什麼會先進行LEFT JOIN然後再進行Filter呢?因為SQL Server根本無法很智能的識别LEFT JOIN上緊跟着的IS NULL,是以需要兩步操作來完成。此時我們需要過濾100萬條資料,這是一個非常耗時的工作,是以此時利用非常高效的Hash Match并且是并行的,但是過濾這些值還是要花費很長時間。整個時間花費了0.989秒,其查詢耗費時間是NOT EXISTS或者NOT IN的3倍。是以到這裡,關于此三者我們可以定下如下這樣一個結論。

NOT IN VS NOT EXISTS VS LEFT JOIN..IS NULL結論:當查詢預設值時利用NOT EXISTS和NOT IN是最佳方式,但是前提是二者查詢列都不能為NULL,否則使用NOT EXISTS。而LEFT JOIN...IS NULL因其總是不會跳過已經比對過的值而是利用先傳回所有結果集然後過濾的方式,其低效性可想而知。

本節我們比較了NOT EXISTS和NOT IN和LEFT JOIN..IS NULL的性能,最終得出了三者性能分析結論,下一節我們已經确定是最後一篇終極篇比較EXISTS VS IN VS JOIN的性能,簡短的内容,深入的了解,我們下節再會。