2013-01-05 20 views
6

नीचे एक संग्रहीत प्रक्रिया (संक्षिप्तता को छोटा) के अंदर एक एसक्यूएल बयान है:MySQL कहां नहीं बेहद धीमी गति से

SELECT * 
FROM item a 
WHERE a.orderId NOT IN (SELECT orderId FROM table_excluded_item); 

यह बयान 30 सेकंड का समय लगता है! लेकिन अगर मैं आंतरिक चयन क्वेरी को हटा देता हूं, तो यह 1s तक गिर जाता है। table_excluded_item बहुत बड़ा नहीं है, लेकिन मुझे संदेह है कि आंतरिक क्वेरी को इसके मुकाबले ज्यादा निष्पादित किया जा रहा है।

क्या ऐसा करने का कोई और अधिक प्रभावी तरीका है?

+1

आंतरिक क्वेरी एक आश्रित सबक्वायरी है, जो कुख्यात बाधाएं हैं क्योंकि बाहरी क्वेरी की प्रत्येक पंक्ति के विरुद्ध सबक्वायरी चलाया जाता है। MySQL dev साइट पर [ऑप्टिमाइज़िंग सबक्वायरीज़] (http://dev.mysql.com/doc/refman/5.1/en/optimizing-subqueries.html) देखें। – Anthony

उत्तर

14

उपयोग LEFT JOIN

SELECT a.* 
FROM item a 
     LEFT JOIN table_excluded_item b 
      ON a.orderId = b.orderId 
WHERE b.orderId IS NULL 

सुनिश्चित करें कि orderId दोनों तालिकाओं से अनुक्रमित किया गया है बनाते हैं।

+0

अरे, यह काम करता है, धन्यवाद! अब यह 2 एस तक है। भाषा हमेशा मेरे लिए बहुत प्रतिद्वंद्वी प्रतीत होती है :( – pixelfreak

+0

आपका स्वागत है ': डी' –

1

इस बाहर की कोशिश करो और LEFT JOIN क्वेरी समय से तुलना करें:

SELECT * 
FROM item a 
HAVING orderId NOT IN (SELECT orderId FROM table_excluded_item); 

यह HAVING के बाद से (HAVING का उपयोग करते समय WHERE इस्तेमाल किया जा सकता) पर सिकोड़ी मानता है कि सीमित हालत (orderId) परिणाम का हिस्सा है सेट। लेकिन मुझे लगता है कि इस परिदृश्य में यह अधिक समझ में आता है (क्योंकि यह परिणाम सेट का हिस्सा है) और क्योंकि यह स्पष्ट है कि LEFT JOIN दृष्टिकोण से क्या चल रहा है।

यह वास्तव में थोड़ा धीमा हो सकता है, लेकिन परिणाम पोस्ट करें ताकि हम जान सकें कि यह आपकी मूल क्वेरी से बेहतर है या नहीं।

+0

चीयर्स - मेरे डेटासेट पर मुझे लगातार बनाम ~ 8s के लिए ~ 7s मिला है ताकि बाएं जुड़ने के दृष्टिकोण – hoju

5

बाएं जुड़ने के दृष्टिकोण के साथ समस्या यह है कि आउटपुट उत्पन्न करने में डुप्लिकेट रिकॉर्ड संसाधित किए जा सकते हैं। कभी-कभी, यह मामला नहीं है। । । इस article के अनुसार, MySQL कॉलम अनुक्रमित होने पर, डुप्लिकेट की उपस्थिति में भी left outer join को सही ढंग से अनुकूलित करता है। मैं संदेह छोड़ने के लिए स्वीकार करता हूं, हालांकि, यह अनुकूलन हमेशा होता है।

MySQL कभी-कभी उपशीर्षक के साथ IN कथन अनुकूलित करने में समस्याएं होती है। सबसे अच्छा ठीक एक सहसंबद्ध सबक्वेरी है:

SELECT * 
FROM item a 
WHERE not exists (select 1 
        from table_excluded_item tei 
        where tei.orderid = a.orderid 
        limit 1 
       ) 

आप table_excluded_item.orderid पर एक सूचकांक है, तो इस सूचकांक को स्कैन और पहले मूल्य में बंद हो जाएगी (limit 1 इस के लिए सख्ती से आवश्यक नहीं हो सकता)। MySQL में जो भी आप चाहते हैं उसे लागू करने का यह सबसे तेज़ और सुरक्षित तरीका है।

+2

तकनीकी रूप से 'सीमा 1' है जरूरी नहीं है; "एंटी-जॉइन" वैसे भी वही काम करेगा। (यह * हो सकता है * कि mysql यह जानने के लिए पर्याप्त स्मार्ट नहीं है) – wildplasser

+0

"बाएं जुड़ने के दृष्टिकोण में समस्या यह है कि आप डुप्लिकेट रिकॉर्ड प्राप्त कर सकते हैं आउटपुट। "- क्यों? याद रखें कि आप अस्तित्वहीन रिकॉर्ड की तलाश में हैं। –

+0

@jW ... मैंने इसे दोहराया। –

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