मैं हमेशा NOT EXISTS
. के लिए डिफ़ॉल्ट हूं ।
निष्पादन योजनाएं इस समय समान हो सकती हैं लेकिन यदि भविष्य में किसी भी कॉलम को NULL
की अनुमति देने के लिए बदल दिया जाता है NOT IN
संस्करण को और अधिक काम करने की आवश्यकता होगी (भले ही कोई NULL
. न हो s वास्तव में डेटा में मौजूद हैं) और शब्दार्थ NOT IN
अगर NULL
ये हैं वर्तमान में वैसे भी होने की संभावना नहीं है जो आप चाहते हैं।
जब न तो 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)
सटीक योजना भिन्न हो सकती है लेकिन मेरे उदाहरण डेटा के लिए मुझे निम्नलिखित मिलते हैं।
एक आम गलत धारणा यह प्रतीत होती है कि सहसंबद्ध उप प्रश्न हमेशा जुड़ने की तुलना में "खराब" होते हैं। वे निश्चित रूप से तब हो सकते हैं जब वे नेस्टेड लूप योजना (पंक्ति द्वारा उप क्वेरी मूल्यांकन पंक्ति) को मजबूर करते हैं लेकिन इस योजना में एंटी सेमी जॉइन लॉजिकल ऑपरेटर शामिल है। एंटी सेमी जॉइन नेस्टेड लूप्स तक ही सीमित नहीं हैं, लेकिन हैश या मर्ज (इस उदाहरण में) जॉइन का भी उपयोग कर सकते हैं।
/*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].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)
इसका कारण यह है कि सही शब्दार्थ यदि [Order Details]
इसमें कोई भी NULL
शामिल है ProductId
s कोई परिणाम नहीं लौटाना है। इसे सत्यापित करने के लिए अतिरिक्त एंटी सेमी जॉइन और रो काउंट स्पूल देखें जो कि योजना में जोड़ा गया है।
अगर 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)
इसका कारण यह है कि एक NULL
Products.ProductId
परिणामों में नहीं लौटाया जाना चाहिए सिवाय अगर NOT IN
उप क्वेरी को कोई परिणाम नहीं लौटाना था (यानी [Order Details]
टेबल खाली है)। किस मामले में चाहिए। मेरे नमूना डेटा की योजना में इसे नीचे के रूप में एक और एंटी सेमी जॉइन जोड़कर लागू किया गया है।
इसका प्रभाव बकले द्वारा पहले से लिंक किए गए ब्लॉग पोस्ट में दिखाया गया है। उदाहरण में तार्किक पढ़ने की संख्या लगभग 400 से 500,000 तक बढ़ जाती है।
इसके अतिरिक्त तथ्य यह है कि एक एकल NULL
पंक्ति संख्या को शून्य तक कम कर सकता है जिससे कार्डिनैलिटी का अनुमान बहुत मुश्किल हो जाता है। यदि SQL सर्वर मानता है कि ऐसा होगा लेकिन वास्तव में कोई NULL
नहीं था डेटा में पंक्तियाँ शेष निष्पादन योजना भयावह रूप से बदतर हो सकती हैं, यदि यह एक बड़ी क्वेरी का सिर्फ एक हिस्सा है, जिसमें अनुपयुक्त नेस्टेड लूप उदाहरण के लिए एक महंगे उप-वृक्ष के बार-बार निष्पादन का कारण बनते हैं।
NOT IN
. के लिए यह एकमात्र संभावित निष्पादन योजना नहीं है एक NULL
. पर -सक्षम कॉलम हालांकि। यह आलेख AdventureWorks2008
. के विरुद्ध एक प्रश्न के लिए दूसरा आलेख दिखाता है डेटाबेस।
NOT IN
के लिए एक पर NOT NULL
कॉलम या NOT EXISTS
एक अशक्त या अशक्त स्तंभ के सामने यह निम्नलिखित योजना देता है।
जब कॉलम NULL
में बदल जाता है -सक्षम NOT IN
योजना अब इस तरह दिखती है
यह योजना में एक अतिरिक्त इनर जॉइन ऑपरेटर जोड़ता है। इस उपकरण को यहां समझाया गया है। पिछले एकल सहसंबद्ध अनुक्रमणिका को Sales.SalesOrderDetail.ProductID = <correlated_product_id>
पर परिवर्तित करने के लिए यह सब कुछ है प्रति बाहरी पंक्ति में दो मांगता है। अतिरिक्त एक WHERE Sales.SalesOrderDetail.ProductID IS NULL
पर है .
जैसा कि यह एक एंटी सेमी जॉइन के तहत है, अगर वह कोई पंक्ति लौटाता है तो दूसरी तलाश नहीं होगी। हालांकि अगर Sales.SalesOrderDetail
इसमें कोई NULL
नहीं है ProductId
s यह आवश्यक खोज कार्यों की संख्या को दोगुना कर देगा।