天天看點

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

本節我們來分析LEFT JOIN和NOT EXISTS,簡短的内容,深入的了解,Always to review the basics。

之前我們已經分析過IN查詢在處理空值時是基于三值邏輯,隻要子查詢中存在空值此時則沒有任何資料傳回,而LEFT JOIN和NOT EXISTS無論子查詢中有無空值上處理都是一樣的,當然比較重要的是利用LEFT JOIN...IS NULL來檢查NULL。基于二者傳回的結果集是一樣的,下面我們開始直接用前面節所建立表來進行測試。在BigTable和SmallerTable上首先未建立索引

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

二者執行CPU Time和elapsed Time如下

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

我們看到上述查詢計劃未建立索引之前二者在開銷上接近一緻,而LEFT JOIN....IS NULL則首先進行哈希比對中的右外部聯接,然後就是過濾,換句話說是LEFT JOIN....IS NULL會直接完全JOIN,然後再對重複資料進行過濾,而NOT EXISTS則是直接利用哈希比對中的右半聯接,關于半聯接我們在前面也已經說過,此時若有重複資料直接隻取一個。是以LEFT JOIN....IS NULL和NOT EXISTS二者對于重複資料一個通過兩部操作完成先完全JOIN後進行過濾,而另外一個則是直接通過右半聯接過濾。是以對于此二者最大的不同在于:當使用LEFT JOIN.....IS NULL時,SQL還沒有那麼聰明,僅僅隻檢查一次,是以它需要通過完全JOIN和過濾來完成,而NOT EXISTS則是在JOIN時就進行過濾。

在看二者執行CPU TIME和elapsed TIME時間,沒有太大的差異。接下來我們再來建立索引看看。

看看二者的查詢執行計劃

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

此時我們通過看到上述查詢執行計劃,我們能夠清楚的看到LEFT JOIN....IS NULL還是完全JOIN然後在過濾,隻是建立了索引之後性能改善了一點而已,但是不同于LEFT JOIN...IS NULL的NOT EXISTS的計劃執行情況不同于未建立索引,此時首先利用了流聚合然後哈希比對中的右半聯接變成了合并聯接中的右半聯接,我們一個個來看,這個Stream Aggregate(流聚合)是什麼鬼,對于此流聚合我是不了解的,不能裝懂,我們接下來具體講講流聚合,至于為什麼每當查詢計劃出現一個新的名詞都要去詳細了解下的原因,相信看過我SQL Server本系列的童鞋知道,每一節的内容都非常短,不會出現閱讀疲勞,而且是精講,我重頭系統學習SQL Server是為了對SQL Server中所有涉及到對性能調優有關的地方以及一些基礎知識都會去過一遍,以便後續再出現性能調優不至于束手無策。好了,回到話題,我們看看Stream Aggregate。

通過上述定義僅僅隻是知道Stream Aggregate是用對行或者列進行聚合,至于什麼時候在查詢計劃中出現流聚合,什麼時候利用流聚合來提高查詢性能都是不得而知,我們接下來一起探讨下。上述着重在于【分組】然後進行【聚合】計算,基于這點我們來看看使用Stream Aggregate的三種場景。

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

上述查詢使用通過DISTINCT,實際上是對cutid進行了分組。以上是用到了Stream Aggregate的場景,當然聚合還有另外一種就是哈希比對聚合,後續會再進行補充。我們再來了解Stream Aggregate定義,我們将定義概括為對輸入進行排序後,接下來進行分組然後再進行聚合計算。在上述(2)和(3)中都是進行了分組,但是沒有排序,實際上内部已經預設實作了排序,我們看下在(3)中表中custid資料,如下

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

當進行DISTINCT之後

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

但是在(3)中沒有進行聚合,為什麼會進行流聚合呢?實際上在流聚合中存在狀态變量,狀态變量具體個數根據聚合個數而定,此狀态變量用來設定結果集,當進行分組後對應的資料進行儲存,此時對應的狀态變量為0,當比對到對應資料時此時狀态變量加1,是以上述(3)中可以說隐式進行了聚合計算,隻是每條資料對應的狀态變量為0而已,到了這裡就不難解釋,隻進行了排序,分組而沒有進行聚合計算的原因。關于Stream Aggregate都知道的一個例子則是我們在利用SqlDataReader記性讀取資料時,可以說是讀取流記錄,如果我們需要彙總結果集時,此時每當Read時,其内部的狀态變量都會加1最終傳回彙總和到用戶端。在這裡我們隻是簡單講講Stream Aggregate,後續會一并講講Hash Aggregate。我們繼續回到LEFT JOIN....IS NULL和NOT EXISTS話題,當我們建立索引之後此時LEFT JOIN....IS ISNULL執行時間是NOT EXISITS的兩倍多。到此,關于LEFT JOIN...IS NULL和NOT EXISTS就此結束,我們同樣下個基本結論。

LEFT JOIN...IS NULL和NOT EXISTS性能分析結論:當我們需要找到子查詢中不比對的行并且列為可空時,此時用NOT EXISTS,當需要找到子查詢中不比對的行,此時列不為空時可以用NOT EXISTS或者NOT IN。

由于LEFT JOIN..IS NULL對于不比對的行不會立即進行傳回而先需要完全JOIN後過濾,尤其是當有多個條件時,LEFT JOIN...IS NULL可能會更加影響查詢性能。

本節我們學習了LEFT JOIN..IS NULL和NOT EXISTS的性能分析,下節我們進入這幾節内容的綜合篇,綜合比較NOT IN VS NOT EXISTS VS LEFT JOIN...IS NULL終極篇。簡短的内容,深入的了解,我們下節再會。