翻譯|使用教程|編輯:楊鵬連|2021-01-06 11:30:22.540|閱讀 339 次
概述:Phil Factor解釋了在使用子查詢比較數(shù)據(jù)集時(shí),為什么您更應(yīng)該使用[NOT] EXISTS而不是[NOT] IN。盡管不再具有顯著的性能優(yōu)勢(shì),但是當(dāng)子查詢的源數(shù)據(jù)包含NULL值時(shí),使用NOT EXISTS可以避免出現(xiàn)意外結(jié)果。
# 界面/圖表報(bào)表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
相關(guān)鏈接:
SQL Prompt是一款實(shí)用的SQL語(yǔ)法提示工具。SQL Prompt根據(jù)數(shù)據(jù)庫(kù)的對(duì)象名稱、語(yǔ)法和代碼片段自動(dòng)進(jìn)行檢索,為用戶提供合適的代碼選擇。自動(dòng)腳本設(shè)置使代碼簡(jiǎn)單易讀--當(dāng)開(kāi)發(fā)者不大熟悉腳本時(shí)尤其有用。SQL Prompt安裝即可使用,能大幅提高編碼效率。此外,用戶還可根據(jù)需要進(jìn)行自定義,使之以預(yù)想的方式工作。
在使用子查詢比較數(shù)據(jù)集時(shí),過(guò)去曾經(jīng)是EXISTS邏輯運(yùn)算符比IN更快。例如,在查詢必須執(zhí)行特定任務(wù)的情況下,但僅當(dāng)子查詢返回任何行時(shí),然后在評(píng)估WHERE [NOT] EXISTS(子查詢)時(shí),數(shù)據(jù)庫(kù)引擎只要發(fā)現(xiàn)一個(gè)就可以退出搜索行,而WHERE [NOT] IN(子查詢) 將始終在進(jìn)一步處理之前從子查詢中收集所有結(jié)果。
但是,查詢優(yōu)化器現(xiàn)在會(huì)盡可能以相同的方式對(duì)待EXISTS和IN,因此您不太可能看到任何明顯的性能差異。但是,如果子查詢的源數(shù)據(jù)包含NULL值,則在使用NOT IN運(yùn)算符時(shí)需要謹(jǐn)慎。如果是這樣,則應(yīng)考慮使用NOT EXISTS運(yùn)算符而不是NOT IN,或者將語(yǔ)句重鑄為左外部聯(lián)接。
SQL Prompt(PE019)中的代碼分析規(guī)則中包含了建議使用[NOT] EXISTS而不是[NOT] IN的建議。
 
	哪種效果更好:EXISTS或IN ....?
有兩種方法可以計(jì)算出兩個(gè)數(shù)據(jù)集之間的差異,但是最常見(jiàn)的兩種方法是使用EXISTS或IN邏輯運(yùn)算符。想象一下,我們有兩個(gè)簡(jiǎn)單的表,一個(gè)表包含英語(yǔ)中的所有常用單詞(CommonWords),另一個(gè)表包含Bram Stoker的“ Dracula”中的所有單詞的列表(WordsInDracula)。該TestExistsAndIn下載包括腳本來(lái)創(chuàng)建這兩個(gè)表,并填充和與之相關(guān)的文本文件中每一個(gè)。通常,在沙盒服務(wù)器中擁有這樣的表對(duì)于在進(jìn)行開(kāi)發(fā)工作時(shí)運(yùn)行測(cè)試很有用,盡管您可以選擇使用的書!
	在德古拉語(yǔ)中有多少個(gè)不常見(jiàn)的單詞?假設(shè)NULL該CommonWords.Word列中沒(méi)有值(稍后會(huì)詳細(xì)介紹),則以下查詢將返回相同的結(jié)果(1555個(gè)字),并具有相同的執(zhí)行計(jì)劃,這在兩個(gè)之間使用了合并聯(lián)接(Right Anti Semi Join)表。
--using NOT IN SELECT Count(*) FROM dbo.WordsInDracula WHERE word NOT IN (SELECT CommonWords.word FROM dbo.CommonWords); --Using NOT EXISTS SELECT Count(*) FROM dbo.WordsInDracula WHERE NOT EXISTS (SELECT * FROM dbo.CommonWords WHERE CommonWords.word = WordsInDracula.word);清單1
簡(jiǎn)而言之,SQL Server優(yōu)化器以相同的方式處理任一查詢,它們也將執(zhí)行相同的查詢。
	…或任何其他(除內(nèi)部聯(lián)接,外部聯(lián)接或相交之外)?
什么其他所有可能的技術(shù),但是,如使用ANY,EXCEPT,INNER JOIN,OUTER JOIN或INTERSECT?清單2顯示了我可以輕松想到的另外七個(gè)替代方案,盡管還有其他替代方案。
--using ANY
SELECT Count(*)
  FROM dbo.WordsInDracula 
WHERE NOT(WordsInDracula.word = ANY  
(SELECT word  
    FROM commonwords )) ;  
--Right anti semi merge join
 
--using EXCEPT
SELECT Count(*)
  FROM
    (
    SELECT word
      FROM dbo.WordsInDracula
    EXCEPT
    SELECT word
      FROM dbo.CommonWords
    ) AS JustTheUncommonOnes;
--Right anti semi merge join
 
--using LEFT OUTER JOIN 
SELECT Count(*)
  FROM dbo.WordsInDracula
    LEFT OUTER JOIN dbo.CommonWords
      ON CommonWords.word = WordsinDracula.word
  WHERE CommonWords.word IS NULL;
--right outer merge join
 
--using FULL OUTER JOIN 
SELECT Count(*)
  FROM dbo.WordsInDracula
    full OUTER JOIN dbo.CommonWords
      ON CommonWords.word = WordsinDracula.word
  WHERE CommonWords.word IS NULL;
--Full outer join implemented as a merge join.
 
--using intersect to get the difference
SELECT (SELECT Count(*) FROM WordsInDracula)-Count(*)
  FROM
    (
    SELECT word
      FROM dbo.WordsInDracula
    intersect
    SELECT word
      FROM dbo.CommonWords
    ) AS JustTheUncommonOnes;
--inner merge join
 
--using FULL OUTER JOIN syntax to get the difference
SELECT Count(*)-(SELECT Count(*) FROM CommonWords)
FROM dbo.WordsInDracula
    full OUTER JOIN dbo.CommonWords
      ON CommonWords.word = WordsinDracula.word
--full outer merge join
 
--using INNER JOIN syntax to get the difference
SELECT (SELECT Count(*) FROM WordsinDracula)-Count(*)
FROM dbo.WordsInDracula
    INNER JOIN dbo.CommonWords
      ON CommonWords.word = WordsinDracula.word
--inner merge join
清單2所有這9個(gè)查詢都給出相同的結(jié)果,但有沒(méi)有一種方法的效果更好?讓我們將它們?nèi)糠湃胍粋€(gè)簡(jiǎn)單的測(cè)試工具中,看看每個(gè)版本需要多長(zhǎng)時(shí)間!再次,代碼下載文件包括測(cè)試工具代碼以及所有九個(gè)查詢。
結(jié)果表明,盡管查詢看起來(lái)有很大不同,但對(duì)于優(yōu)化程序而言,它通常只是“語(yǔ)法糖”。無(wú)論您的SQL有多優(yōu)雅,優(yōu)化器都只會(huì)聳聳肩,并提出執(zhí)行它的有效計(jì)劃。實(shí)際上,前四個(gè)都使用完全相同的“正確的半合并合并”執(zhí)行計(jì)劃,并且都花費(fèi)相同的時(shí)間。
		 
	
 
	NOT IN的陷阱
比較具有空值的集合存在一定的不現(xiàn)實(shí)性,但是如果在每天的數(shù)據(jù)庫(kù)報(bào)告熱中發(fā)生這種情況,則可能會(huì)出錯(cuò)。如果NULL子查詢或表達(dá)式的結(jié)果中有一個(gè)值傳遞給IN邏輯運(yùn)算符,則它將給出合理的響應(yīng),并且與等效值相同EXISTS。但是,NOT IN行為卻大不相同。
	清單3演示了這個(gè)問(wèn)題。我們?cè)贎someWord表變量中插入三個(gè)常用詞和三個(gè)不常用詞,并且我們想知道不在表變量中的常用詞的數(shù)量。
SET NOCOUNT ON;
DECLARE @someWord TABLE
(
    word NVARCHAR(35) NULL
);
INSERT INTO @someWord
(
    word
)
--three common words
SELECT TOP 3
       word
FROM dbo.commonwords
ORDER BY word DESC;
 
-- three uncommon words
INSERT INTO @someWord
(
    word
)
VALUES
('flibberty'),
('jibberty'),
('flob');
 
SELECT [NOT EXISTS without NULL] = COUNT(*)
FROM commonwords AS MyWords
WHERE NOT EXISTS
(
    SELECT word FROM @someWord AS s WHERE s.word LIKE MyWords.word
);
 
SELECT [NOT IN without NULL] = COUNT(*)
FROM commonwords AS MyWords
WHERE word NOT IN (
                      SELECT word FROM @someWord
                  );
 
--Insert a NULL value
INSERT INTO @someWord
(
    word
)
VALUES
(NULL);
 
SELECT [NOT EXISTS with NULL] = COUNT(*)
FROM commonwords AS MyWords
WHERE NOT EXISTS
(
    SELECT word FROM @someWord AS s WHERE s.word LIKE MyWords.word
);
SELECT [NOT IN with NULL] = COUNT(*)
FROM commonwords AS MyWords
WHERE word NOT IN (
                      SELECT word FROM @someWord
                  );
清單3
在NOT IN查詢時(shí),才插入NULL到@someword,并且兩個(gè)NOT EXISTS查詢,所有正確地告訴我們,60385點(diǎn)的話是不是在我們的表變量,因?yàn)槿迹⒂性谒?0388個(gè)常用詞。但是,如果子查詢可以返回NULL,則NOT IN根本不返回任何行。
		 
	
	從邏輯上講,SQL Server評(píng)估子查詢,將其替換為其返回的值列表,然后評(píng)估[NOT] IN條件。對(duì)于IN我們查詢的變體,這不會(huì)引起問(wèn)題,因?yàn)樗梢越鉀Q以下問(wèn)題:
  WHERE word = 'flibberty' OR word = 'jibberty' OR word = 'flob'
     OR word = 'zygotes' OR word = 'zygote' OR word = 'zydeco'
     OR word = NULL;
對(duì)于“ z…”字樣的匹配項(xiàng),將返回3行。附帶了刺N(yùn)OT IN,它可以解決以下問(wèn)題:  WHERE word <> 'flibberty' AND word <> 'jibberty'AND word <> 'flob'
    AND word <> 'zygotes' AND word <> 'zygote' AND word <> 'zydeco'
    AND word <> NULL;
AND具有要比較的條件的結(jié)果NULL為'unknown',因此表達(dá)式將始終返回零行。這不是錯(cuò)誤;這是設(shè)計(jì)使然。您可以辯稱,NULL不應(yīng)在要使用NOT IN表達(dá)式的任何列中使用a ,但是在我們的實(shí)際工作中,這些東西可能會(huì)滲入表源。值得謹(jǐn)慎。因此,請(qǐng)使用EXISTS變體或其他變體,或始終記住WHERE在IN條件中包含一個(gè)從句以消除NULLs。
試用下載>>>
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請(qǐng)務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請(qǐng)郵件反饋至chenjj@ke049m.cn
文章轉(zhuǎn)載自: