2012-04-24 11 views
39

यह मानते हुए कि मैं निम्नलिखित T-SQL कोड का उपयोग करते हुए:कहां खंड बनाम पर जब शामिल हों

SELECT * FROM Foo f 
INNER JOIN Bar b ON b.BarId = f.BarId; 
WHERE b.IsApproved = 1; 

के बाद एक भी पंक्तियों का एक ही सेट रिटर्न:

SELECT * FROM Foo f 
INNER JOIN Bar b ON (b.IsApproved = 1) AND (b.BarId = f.BarId); 

यह नहीं हो सकता है यहां सबसे अच्छा केस नमूना है लेकिन क्या इन दोनों के बीच कोई प्रदर्शन अंतर है?

+2

यहां एक समान प्रश्न है: http://stackoverflow.com/questions/2509987/which-sql-query-is-faster-filter-on-join-criteria-or-where-clause –

+11

मशीन इसे समझ लेगी और इसे ठीक से अनुकूलित करें। हालांकि, उन मनुष्यों के लिए जिन्हें अब से आपके कोड वर्षों को \ संशोधित \ संशोधित करने की आवश्यकता होगी, फ़िल्टरिंग शर्तों को 'WHERE' में रखें और 'ON' में स्थितियों में शामिल हों। –

+0

@ केएम। मैं हमेशा यह नहीं जानता कि कैसे जुड़ाव की स्थिति और फ़िल्टर क्या है, के बीच अंतर कैसे बताना है। उदाहरण के लिए [इस उत्तर में] (http://stackoverflow.com/a/9303069/119477) मुझे लगता है कि इसमें शामिल होने में बेहतर यह है कि "स्थिति में शामिल हों" तो? [यहां एक और उदाहरण है] (http://stackoverflow.com/a/6473403/119477) जो मुझे यह भी नहीं पता कि समकक्ष जहां समकक्ष को फिर से लिखना है। –

उत्तर

28

नहीं, क्वेरी ऑप्टिमाइज़र दोनों उदाहरणों के लिए एक ही निष्पादन योजना चुनने के लिए पर्याप्त स्मार्ट है।

आप निष्पादन योजना की जांच के लिए SHOWPLAN का उपयोग कर सकते हैं।


फिर भी, आप सभी और ON खंड पर कनेक्शन WHERE खंड पर सभी प्रतिबंधों में शामिल होने रखना चाहिए।

+2

मुझे इसे मारो। हालांकि वरीयता के मामले में, मैं जॉइन के साथ जाऊंगा क्योंकि यह अधिक वर्णनात्मक है। – Ste

+1

धन्यवाद! 7 या 8 इनर जॉइन के साथ एक परिस्थिति की कल्पना करो। क्या आपका उत्तर उन परिस्थितियों पर भी लागू है? – tugberk

+13

@ एसटीई आईएमओ, यह वास्तव में 'जॉइन' में सबकुछ डालने में अधिक भ्रमित है। किसी क्वेरी में तालिकाओं से संबंधित 'जॉइन' का उपयोग करें। परिणामों को फ़िल्टर करने के लिए 'WHERE' का उपयोग करें। यह तब होता है जब आप दो मिश्रण करते हैं और केवल ** एक या दूसरे का उपयोग करते हैं जो प्रश्न पढ़ने के लिए कठिन हो जाते हैं। – Yuck

5
SELECT * FROM Foo f 
INNER JOIN Bar b ON b.BarId = f.BarId 
WHERE b.IsApproved = 1; 

यह जाने का बेहतर तरीका है। इसे पढ़ने और संशोधित करने में आसान है। व्यापारिक दुनिया में यही वह है जिसे आप साथ जाना चाहते हैं। जहां तक ​​प्रदर्शन वे वही हैं।

+0

मेरी वर्तमान स्थिति में, मैं WHERE क्लॉज का पक्ष लेता हूं लेकिन अगर कोई perf diff है तो सोचने से बच नहीं पाए। धन्यवाद! – tugberk

42

बाहरी जुड़ने के साथ अंतर से सावधान रहें। एक क्वेरी जहां b.IsApproved के एक फिल्टर (सही मेज पर, बार) JOIN की ON हालत में जोड़ा जाता है:

:

SELECT * 
FROM Foo f 
LEFT OUTER JOIN Bar b ON (b.IsApproved = 1) AND (b.BarId = f.BarId); 

नहींWHERE खंड में फिल्टर देना एक ही है

SELECT * 
FROM Foo f 
LEFT OUTER JOIN Bar b ON (b.BarId = f.BarId) 
WHERE (b.IsApproved = 1); 

'विफल' के लिए के बाद से बाहरी Bar (यानी जहां एक f.BarId के लिए कोई b.BarId है), इस b.IsApprovedNULL के रूप में इस तरह के सभी पिता के लिए छोड़ देंगे करने के लिए मिलती है उबला हुआ पंक्तियां, और इन पंक्तियों को फिर फ़िल्टर किया जाएगा।

इस को देखने का एक और तरीका है कि पहले प्रश्न के लिए, LEFT OUTER JOIN Bar b ON (b.IsApproved = 1) AND (b.BarId = f.BarId) हमेशा बाईं तालिका पंक्तियों वापस आ जाएगी, क्योंकि LEFT OUTER JOIN की गारंटी देता है वाम तालिका पंक्तियों भले ही में शामिल होने में विफल रहता है लौटा दी जाएगी है। हालांकि, (b.IsApproved = 1) को LEFT OUTER JOIN पर LEFT OUTER JOIN पर जोड़ने के प्रभाव को (b.IsApproved = 1) पर कोई सही तालिका कॉलम न्यूल करना है, यानी पर सामान्य रूप से LEFT JOIN स्थिति पर लागू नियमों के अनुसार।

अद्यतन: सवाल कॉनराड द्वारा पूछे जाने पर पूरा करने के लिए, एक वैकल्पिक फिल्टर के लिए बराबर LOJ होगा:

यानी
SELECT * 
FROM Foo f 
LEFT OUTER JOIN Bar b ON (b.BarId = f.BarId) 
WHERE (b.IsApproved IS NULL OR b.IsApproved = 1); 

WHERE खंड में शामिल होने के लिए कि क्या दोनों की हालत पर विचार करने की जरूरत है (NULL) विफल रहता है और फिल्टर को अनदेखा किया जाना है, और जहां शामिल हो जाता है और फ़िल्टर लागू किया जाना चाहिए।(b.IsApproved या b.BarIdNULL के लिए परीक्षण किया जा सकता है)

मैं एक SqlFiddle together here जो JOIN को b.IsApproved फिल्टर रिश्तेदार के विभिन्न प्लेसमेंट के बीच मतभेदों को दर्शाता है डाल दिया।

+0

+1, अच्छा बिंदु! –

+0

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

+1

@nonnb ठीक है, लेकिन अगर आपने दूसरी क्वेरी पर WHERE क्लॉज को सही किया है तो 'कहां बी।IsAproved = 1 या b.BarId शून्य है 'यह वही है। अब आप कौन सा करते हैं? –

0

मुझे कुछ ऐसे मामले सामने आए हैं जहां ऑप्टिमाइज़र MSSQL के हाल के संस्करणों पर भी स्मार्ट नहीं था - और प्रदर्शन अंतर राक्षस था।

लेकिन यह एक अपवाद है, अधिकांश समय SQL सर्वर अनुकूलक समस्या का समाधान करेगा और सही योजना प्राप्त करेगा।

तो WHERE क्लॉज पर फ़िल्टर का उपयोग करने की आवश्यकता है और आवश्यकता होने पर अनुकूलित करें।

0

मैंने अभी चार टेबलों के खिलाफ एक प्रश्न का परीक्षण किया - तीन प्रविष्टियों के साथ एक प्राथमिक तालिका और कुल चार पैरामीटर, और दोनों दृष्टिकोणों की निष्पादन योजनाओं की तुलना में (जॉइन के चालू में फ़िल्टर मानदंडों का उपयोग करके, और फिर WHERE खंड में भी)।

निष्पादन योजना बिल्कुल वही हैं। मैंने इसे SQL Server 2008 R2 पर चलाया।

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