2008-10-06 6 views
406

इनमें से कौन सा प्रश्न तेजी से है?नहीं बनाम EXISTS

नहीं मौजूद है:

SELECT ProductID, ProductName 
FROM Northwind..Products p 
WHERE NOT EXISTS (
    SELECT 1 
    FROM Northwind..[Order Details] od 
    WHERE p.ProductId = od.ProductId) 

या नहीं:

SELECT ProductID, ProductName 
FROM Northwind..Products p 
WHERE p.ProductID NOT IN (
    SELECT ProductID 
    FROM Northwind..[Order Details]) 

क्वेरी निष्पादन योजना का कहना है कि वे दोनों एक ही बात करते हैं। यदि ऐसा है, तो अनुशंसित रूप कौन सा है?

यह नॉर्थविंड डेटाबेस पर आधारित है।

[संपादित करें]

बस इस उपयोगी लेख मिला: http://weblogs.sqlteam.com/mladenp/archive/2007/05/18/60210.aspx

मुझे लगता है कि मैं रह सकते हैं मौजूद नहीं है के साथ।

+1

क्या आपने एक बाएं शामिल होने के साथ योजना का प्रयास किया है जहां शून्य है? – Sebas

+1

मुझे आश्चर्य है कि डेटाबेस अलग हैं, लेकिन PostgreSQL के खिलाफ मेरे नवीनतम बेंचमार्क में, यह 'इन नहीं' क्वेरी है: 'चुनें "ए"। * "ए" से "ए"। "आईडी" नहीं (चयन करें "बी"। " सहायता "बी" कहां "बी"। "यूआईडी" = 2) 'लगभग 15 गुना तेज है क्योंकि यह 'पूर्व नहीं है': 'चुनें" ए "। *" ए "से (नहीं (EXISTS (चयन 1) "बी" से "बी"। "User_id" = 2 और "बी"। "सहायता" = "ए"। "आईडी"))) –

+0

संभावित डुप्लिकेट [EXISTS बनाम नहीं बनाम बनाम अंतर के बीच क्या अंतर है बाएं जॉइन कहां है?] (Http://stackoverflow.com/questions/2246772/whats-the-difference-between-not-exists-vs-not-in-vs-left- join-where-is-null) – rcdmk

उत्तर

553

मैं हमेशा NOT EXISTS पर डिफ़ॉल्ट हूं।

निष्पादन की योजना इस समय एक ही हो सकता है, लेकिन यदि या तो स्तंभ भविष्य में बदल दिया जाता है NULL अनुमति देने के लिए है NOT IN संस्करण अधिक काम करने के (भले ही कोई NULL रों वास्तव में डेटा में मौजूद हैं) की आवश्यकता होगी और NOT IN के अर्थशास्त्र यदि NULL s वर्तमान में वैसे भी होने की संभावना नहीं है।

जब न Products.ProductID या [Order Details].ProductID अनुमति देते हैं NULL रों NOT IN निम्न क्वेरी के समान माना जाएगा।

SELECT ProductID, 
     ProductName 
FROM Products p 
WHERE NOT EXISTS (SELECT * 
        FROM [Order Details] od 
        WHERE p.ProductId = od.ProductId) 

सटीक योजना भिन्न हो सकती है लेकिन मेरे उदाहरण डेटा के लिए मुझे निम्न मिलता है।

Neither NULL

एक यथोचित आम धारणा है कि सहसंबद्ध उप प्रश्नों हमेशा मिलती है की तुलना में "बुरा" हैं लगता है। वे निश्चित रूप से तब हो सकते हैं जब वे एक नेस्टेड लूप योजना (पंक्ति द्वारा उप क्वेरी मूल्यांकन पंक्ति) को मजबूर करते हैं लेकिन इस योजना में एक विरोधी सेमीफाइनल लॉजिकल ऑपरेटर शामिल है। एंटी अर्द्ध जॉइन नेस्टेड लूप तक ही सीमित नहीं हैं लेकिन हैश या मर्ज का उपयोग कर सकते हैं (जैसा कि इस उदाहरण में) भी शामिल हो जाता है।

/*Not valid syntax but better reflects the plan*/ 
SELECT p.ProductID, 
     p.ProductName 
FROM Products p 
     LEFT ANTI SEMI JOIN [Order Details] od 
     ON p.ProductId = od.ProductId 

तो [Order Details].ProductIDNULL है सुलभ क्वेरी तो हो जाता है

SELECT ProductID, 
     ProductName 
FROM Products p 
WHERE NOT EXISTS (SELECT * 
        FROM [Order Details] od 
        WHERE p.ProductId = od.ProductId) 
     AND NOT EXISTS (SELECT * 
         FROM [Order Details] 
         WHERE ProductId IS NULL) 

इस का कारण यह सही अर्थ विज्ञान अगर [Order Details] शामिल है कि किसी भी NULLProductId कोई परिणाम देने के है। योजना में जोड़े गए यह सत्यापित करने के लिए अतिरिक्त एंटी सेमी सेमी और पंक्ति गणना स्पूल देखें।

One NULL

तो Products.ProductID भी NULL बनने के लिए सुलभ क्वेरी तो हो जाता है

SELECT ProductID, 
     ProductName 
FROM Products p 
WHERE NOT EXISTS (SELECT * 
        FROM [Order Details] od 
        WHERE p.ProductId = od.ProductId) 
     AND NOT EXISTS (SELECT * 
         FROM [Order Details] 
         WHERE ProductId IS NULL) 
     AND NOT EXISTS (SELECT * 
         FROM (SELECT TOP 1 * 
           FROM [Order Details]) S 
         WHERE p.ProductID IS NULL) 

बदल गया है कि एक के लिए कारण यह है कि एक NULLProducts.ProductId छोड़कर परिणामों में नहीं किया जाना चाहिए यदि NOT IN उप क्वेरी को कोई परिणाम नहीं लौटा रहा था (यानी [Order Details] तालिका खाली है)। इस मामले में यह होना चाहिए। मेरे नमूना डेटा के लिए योजना में यह नीचे एक और विरोधी अर्द्ध शामिल जोड़कर लागू किया गया है।

Both NULL

इस के प्रभाव the blog post already linked by Buckley में दिखाया गया है। उदाहरण में वहां लॉजिकल रीड की संख्या लगभग 400 से 500,000 तक बढ़ जाती है।

इसके अतिरिक्त यह तथ्य कि एक NULL पंक्ति गणना को शून्य तक कम कर सकता है कार्डिनिटी अनुमान बहुत मुश्किल बनाता है। यदि SQL सर्वर मानता है कि ऐसा होगा लेकिन वास्तव में डेटा में NULL पंक्तियां नहीं थीं, शेष निष्पादन योजना विनाशकारी रूप से खराब हो सकती है, अगर यह केवल एक बड़ी क्वेरी का हिस्सा है, with inappropriate nested loops causing repeated execution of an expensive sub tree for example

यह एक NULL सुलभ स्तंभ पर एक NOT IN तथापि के लिए ही संभव कार्य योजना लागू नहीं है। AdventureWorks2008 डेटाबेस के विरुद्ध एक प्रश्न के लिए This article shows another one

एक NOT NULL स्तंभ पर NOT IN या या तो एक नल या गैर व्यर्थ स्तम्भ के खिलाफ NOT EXISTS यह निम्न योजना देता है के लिए

Not EXists

NULL करने के लिए स्तंभ परिवर्तन सुलभ NOT IN योजना अब लग रहा है जब

तरह

Not In - Null

यह एक अतिरिक्त भीतरी कहते योजना के लिए ऑपरेटर में शामिल हो। यह उपकरण explained here है। पिछले एकल सहसंबंधित इंडेक्स को Sales.SalesOrderDetail.ProductID = <correlated_product_id> पर दो बाहरी पंक्तियों की तलाश में बदलने के लिए यह सब कुछ है। अतिरिक्त एक WHERE Sales.SalesOrderDetail.ProductID IS NULL पर है।

चूंकि यह एक अर्द्ध अर्द्ध शामिल है, यदि कोई भी पंक्तियों को वापस करता है तो दूसरा प्रयास नहीं होगा। हालांकि अगर Sales.SalesOrderDetail में कोई NULLProductID नहीं है तो यह आवश्यक संचालन संचालन की संख्या को दोगुना कर देगा।

+3

क्या मैं पूछ सकता हूं कि कैसे आपको दिखाए गए प्रोफाइलिंग ग्राफ मिलते हैं? – xis

+5

@xis ये एसक्यूएल सेंट्री प्लान एक्सप्लोरर में निष्पादन योजनाएं खोली गई हैं। आप एसएसएमएस में ग्राफिकल रूप से निष्पादन योजना भी देख सकते हैं। –

+0

मैं इस एकमात्र कारण के लिए सराहना करता हूं कि: 'EXISTS' कार्य करने की अपेक्षा नहीं करता है जिस तरह से मैं काम नहीं करता हूं (जो, यह नहीं करता)। – levininja

22

यदि निष्पादन योजनाकार कहता है कि वे वही हैं, तो वे वही हैं। जो भी कोई भी आपके इरादे को और अधिक स्पष्ट करेगा, इस मामले में, दूसरा।

+2

निष्पादन योजनाकार समय समान हो सकता है लेकिन निष्पादन परिणाम भिन्न हो सकते हैं इसलिए एक है अंतर। यदि आपके पास अपने डेटासेट में न्यूल है (बक्ली का जवाब देखें) अप्रत्याशित परिणाम नहीं देगा। डिफॉल्ट के रूप में EXISTS का उपयोग करने के लिए सर्वश्रेष्ठ। – nanonerd

+0

इस उदाहरण में, उत्पाद आईडी एक कुंजी (शून्य नहीं) फ़ील्ड है, इसलिए जो भी ... – Philippe

0

यह निर्भर करता है ..

SELECT x.col 
FROM big_table x 
WHERE x.key IN(SELECT key FROM really_big_table); 

अपेक्षाकृत धीमी गति से अगर वे कुंजी में है क्या देखने के लिए क्वेरी की जांच के आकार को सीमित करने के लिए काफी नहीं है नहीं होगा। EXISTS इस मामले में बेहतर होगा।

लेकिन, डीबीएमएस के अनुकूलक के आधार पर, यह अलग नहीं हो सकता है।

के रूप में जब मौजूद है की एक उदाहरण के लिए बेहतर है

SELECT x.col 
FROM big_table x 
WHERE EXISTS(SELECT key FROM really_big_table WHERE key = x.key); 
    AND id = very_limiting_criteria 
+1

'IN' और' EXISTS' [SQL सर्वर में एक ही योजना प्राप्त करें] (http://sqlinthewild.co.za/index। php/2009/08/17/मौजूद है-बनाम-इन /)। प्रश्न वैसे भी 'नहीं' बनाम 'नहीं' के बारे में है। "यह निर्भर करता है .." के लिए –

+0

+1। क्लासिक एसक्यूएल उत्तर – whytheq

11

दरअसल, मेरा मानना ​​है कि यह सबसे तेजी से होगा:

SELECT ProductID, ProductName 
    FROM Northwind..Products p 
      outer join Northwind..[Order Details] od on p.ProductId = od.ProductId) 
WHERE od.ProductId is null 
+2

ऑप्टिमाइज़र यह काम कर रहा है जब सबसे तेज़ नहीं हो सकता है, लेकिन यह निश्चित रूप से तेज़ होगा जब यह नहीं है। –

+1

उन्होंने इस पोस्ट के लिए भी अपनी क्वेरी को सरल बना दिया होगा – Kip

+0

सहमत बाएं बाहरी जुड़ना अक्सर एक सबक्वायरी से तेज़ होता है। – HLGEM

5

अपने विशिष्ट उदाहरण में वे एक ही हैं, क्योंकि अनुकूलक पता कर लिया है जो आप करने की कोशिश कर रहे हैं वह दोनों उदाहरणों में समान है। लेकिन यह संभव है कि गैर-तुच्छ उदाहरणों में अनुकूलक ऐसा नहीं कर सकता है, और उस स्थिति में अवसर पर एक दूसरे को पसंद करने के कारण हैं।

यदि आप अपने बाहरी चयन में एकाधिक पंक्तियों का परीक्षण कर रहे हैं तो इन्हें प्राथमिकता नहीं दी जानी चाहिए। नोट इन कथन के अंदर सबक्वायरी का निष्पादन की शुरुआत में मूल्यांकन किया जा सकता है, और अस्थायी तालिका को बाहरी चयन में प्रत्येक मान के विरुद्ध चेक किया जा सकता है, हर बार उप-चयन को फिर से चलाने के बजाए, जैसा कि पूर्ववत विवरण के साथ आवश्यक नहीं होगा ।

सबक्वेरी बाहरी चयन के साथ सहसंबद्ध किया जाना चाहिए, तो मौजूद नहीं है के बाद से अनुकूलक एक सरलीकरण है कि किसी भी अस्थायी तालिकाओं का निर्माण रोकता है एक ही समारोह में प्रदर्शन करने के लिए पता लग सकता है बेहतर हो सकता है।

0

यदि अनुकूलक कहता है कि वे वही हैं तो मानव कारक पर विचार करें। मैं EXISTS नहीं देखना पसंद करता हूं :)

62

यह भी ध्यान रखें कि शून्य में शून्य होने पर EXISTS के बराबर नहीं है।

इस पोस्ट में यह बहुत अच्छी तरह से

http://sqlinthewild.co.za/index.php/2010/02/18/not-exists-vs-not-in/

जब सबक्वेरी रिटर्न भी एक अशक्त, नहीं किसी भी पंक्तियों से मेल नहीं होंगे बताते हैं।

इसका कारण यह देखने के लिए पाया जा सकता है कि वास्तव में ऑपरेशन का मतलब नहीं है।

के तालिका टी कहा जाता है में 4 पंक्तियों देखते हैं कि समझाने के उद्देश्य से कहते हैं, करते हैं, वहाँ एक स्तंभ मान के साथ आईडी कहा जाता है 1..4

WHERE SomeValue NOT IN (SELECT AVal FROM t) 

WHERE SomeValue != (SELECT AVal FROM t WHERE ID=1) 
AND SomeValue != (SELECT AVal FROM t WHERE ID=2) 
AND SomeValue != (SELECT AVal FROM t WHERE ID=3) 
AND SomeValue != (SELECT AVal FROM t WHERE ID=4) 

के बराबर है आइए आगे यह कहें कि एवल नल है जहां आईडी = 4. इसलिए वह! = तुलना UNKNOWN लौटाती है। के लिए तार्किक सत्य तालिका और अनन्य और सत्य अज्ञात है, अज्ञात और गलत गलत है। वहाँ कोई मूल्य नहीं है कि अज्ञात के साथ

इसलिए AND'd जा सकती है, परिणाम सही निर्माण करने के लिए, पूरे नहीं ऑपरेटर में या तो गलत या शून्य और कोई रिकॉर्ड होगा करने के लिए मूल्यांकन करेंगे कि अगर सबक्वेरी के किसी भी पंक्ति NULL भेजता है

2

मैं

SELECT * from TABLE1 WHERE Col1 NOT IN (SELECT Col1 FROM TABLE2) 

उपयोग कर रहा था और पाया कि यह गलत परिणाम दे रहा था (गलत रूप से मैं कोई परिणाम नहीं मतलब)। चूंकि TABLE2.Col1 में एक नल था।

जबकि

SELECT * from TABLE1 T1 WHERE NOT EXISTS (SELECT Col1 FROM TABLE2 T2 WHERE T1.Col1 = T2.Col2) 

करने के लिए क्वेरी को बदलने के लिए मुझे सही परिणाम दे दी है।

तब से मैंने हर जगह EXISTS का उपयोग करना शुरू कर दिया है।

6

मेरे पास एक सारणी है जिसमें लगभग 120,000 रिकॉर्ड हैं और केवल उन लोगों को चुनने की आवश्यकता है जो चार अन्य तालिकाओं में मौजूद नहीं हैं (लगभग वर्चर कॉलम से मेल खाते हैं) पंक्तियों की संख्या लगभग 1500, 4000, 40000, 200. सभी शामिल तालिकाओं में संबंधित Varchar कॉलम पर अद्वितीय अनुक्रमणिका है।

NOT IN में लगभग 10 मिनट, NOT EXISTS ने 4 सेकंड लिया।

मैं एक पुनरावर्ती पूछताछ जो कुछ untuned अनुभाग जो 10 मिनट में योगदान दिया है हो सकता है के लिए किया था हो सकता है है, लेकिन अन्य 4 सेकेंड लेने विकल्प मेरे लिए, बताते हैं कम से कम NOT EXISTS है कि कहीं बेहतर है या नहीं IN और EXISTS हैं कम से कम है कि कोड के साथ आगे बढ़ने से पहले बिल्कुल वही और हमेशा एक चेक के लायक है।

संबंधित मुद्दे