2014-09-10 19 views
12

मैं उत्सुक हूं कि EXISTS() का निष्पादन IN() से तेज़ होना चाहिए।MySQL मौजूदा बनाम बनाम subquery बनाम subquery बनाम?

मैं answering a question था जब बिल करविन ने एक अच्छा बिंदु लाया। जब आप EXISTS() का उपयोग करते हैं तो यह एक सहसंबंधित सबक्वायरी (आश्रित सबक्वायरी) का उपयोग कर रहा है और IN() केवल एक सबक्वायरी का उपयोग कर रहा है।

शो कि EXISTS और NOT EXISTS दोनों एक आश्रित सबक्वेरी और IN/NOT IN दोनों सिर्फ एक सबक्वेरी का उपयोग का उपयोग व्याख्या .. इसलिए मैं उत्सुक कैसे एक सहसंबद्ध सबक्वेरी एक सबक्वेरी की तुलना में तेजी है कर रहा हूँ ??

मैंने पहले EXISTS का उपयोग किया है और यह IN से तेज़ी से निष्पादित करता है, इसलिए मैं उलझन में हूं।

यहाँ के साथ एक SQLFIDDLE, कैसे करता है मौजूद है बताते

EXPLAIN SELECT COUNT(t1.table1_id) 
FROM table1 t1 
WHERE EXISTS 
( SELECT 1 
    FROM table2 t2 
    WHERE t2.table1_id <=> t1.table1_id 
); 

+-------+-----------------------+-----------+-------+---------------+-----------+--------+--------------------------+--------+------------------------------+ 
| ID | SELECT_TYPE   | TABLE | TYPE | POSSIBLE_KEYS | KEY  |KEY_LEN | REF      | ROWS | EXTRA      | 
+-------+-----------------------+-----------+-------+---------------+-----------+--------+--------------------------+--------+------------------------------+ 
| 1 | PRIMARY    | t1  | index | (null)  | PRIMARY | 4 | (null)     | 4 | Using where; Using index | 
| 2 | DEPENDENT SUBQUERY | t2  | REF | table1_id  | table1_id| 4 | db_9_15987.t1.table1_id | 1 | Using where; Using index | 
+-------+-----------------------+-----------+-------+---------------+-----------+--------+--------------------------+--------+------------------------------+ 

EXPLAIN SELECT COUNT(t1.table1_id) 
FROM table1 t1 
WHERE NOT EXISTS 
( SELECT 1 
    FROM table2 t2 
    WHERE t2.table1_id = t1.table1_id 
); 
+-------+-----------------------+-----------+-------+---------------+-----------+--------+--------------------------+--------+------------------------------+ 
| ID | SELECT_TYPE   | TABLE | TYPE | POSSIBLE_KEYS | KEY  |KEY_LEN | REF      | ROWS | EXTRA      | 
+-------+-----------------------+-----------+-------+---------------+-----------+--------+--------------------------+--------+------------------------------+ 
| 1 | PRIMARY    | t1  | index | (null)  | PRIMARY | 4 | (null)     | 4 | Using where; Using index | 
| 2 | DEPENDENT SUBQUERY | t2  | ref | table1_id  | table1_id| 4 | db_9_15987.t1.table1_id | 1 | Using index     | 
+-------+-----------------------+-----------+-------+---------------+-----------+--------+--------------------------+--------+------------------------------+ 

EXPLAIN SELECT COUNT(t1.table1_id) 
FROM table1 t1 
WHERE t1.table1_id NOT IN 
( SELECT t2.table1_id 
    FROM table2 t2 
); 
+-------+-------------------+-----------+-------+---------------+-----------+--------+----------+--------+------------------------------+ 
| ID | SELECT_TYPE  | TABLE | TYPE | POSSIBLE_KEYS | KEY  |KEY_LEN | REF  | ROWS | EXTRA      | 
+-------+-------------------+-----------+-------+---------------+-----------+--------+----------+--------+------------------------------+ 
| 1 | PRIMARY   | t1  | index | (null)  | PRIMARY | 4 | (null) | 4 | Using where; Using index | 
| 2 | SUBQUERY  | t2  | index | (null)  | table1_id| 4 | (null) | 2 | Using index     | 
+-------+-------------------+-----------+-------+---------------+-----------+--------+----------+--------+------------------------------+ 

कुछ सवाल

ऊपर बताते हैं में using where औरहै अतिरिक्त मेंलेकिन EXISTS के पास अतिरिक्त में using where नहीं है?

एक सहसंबंधित उपक्वायर उपखंड से तेज़ कैसे होता है?

+0

तो क्या आपके पास 'अस्तित्व 'का एक रेपो तेजी से निष्पादित है? इसके अलावा आप किस संस्करण पर अनुभव करते थे? 'इन' भी [एक ही समस्या का उपयोग किया जाता था] (http://stackoverflow.com/q/3416076/73226) –

+0

@ मार्टिनस्मिथ अच्छी तरह से मैंने एक साल पहले अपने प्रश्नों को IN से EXISTS में बदल दिया क्योंकि उन्हें EXISTS के साथ तेजी से निष्पादित किया गया था (पूरी तरह से कुछ सेकंड की तरह कुछ सेकंड की तरह नहीं) .. लेकिन मुझे अभी एक नया कंप्यूटर मिला है और MySQL का नवीनतम संस्करण डाउनलोड किया गया है .. मैंने अभी एक प्रश्न चलाया और IN0000 सेकंड तक तेजी से भाग गया ... हाल ही में निष्पादन योजना/अनुकूलक के लिए एक फिक्स किया गया है? –

+0

मुझे माईएसक्ल ऑप्टिमाइज़र के बारे में बहुत कुछ नहीं पता लेकिन मुझे विश्वास है कि 5.6 ने कुछ बदलाव किए हैं। https://dev.mysql.com/doc/refman/5.6/en/subquery-optimization।एचटीएमएल –

उत्तर

8

यह एक आरडीबीएमएस-अज्ञेयवाद जवाब है, लेकिन फिर भी मदद मिल सकती है। मेरी समझ में, सहसंबंधित (उर्फ, आश्रित) सबक्वायरी शायद खराब प्रदर्शन के लिए अक्सर झूठे आरोपी अपराधी है।

समस्या (जैसा कि इसे अक्सर वर्णित किया जाता है) यह है कि यह बाहरी क्वेरी की प्रत्येक पंक्ति के लिए आंतरिक क्वेरी को संसाधित करता है। इसलिए, यदि बाहरी क्वेरी 1,000 पंक्तियां लौटाती है, और आंतरिक क्वेरी 10,000 लौटाती है, तो परिणाम देने के लिए आपकी क्वेरी 10,000,000 पंक्तियों (बाहरी × आंतरिक) के माध्यम से घूमना पड़ता है। एक ही परिणाम सेट पर एक गैर-सहसंबंधित क्वेरी से 11,000 पंक्तियों (बाहरी + भीतरी) की तुलना में, यह अच्छा नहीं है।

हालांकि, यह सबसे खराब स्थिति परिदृश्य है। कई मामलों में, डीबीएमएस पंक्ति गणना को कम करने के लिए इंडेक्स का फायदा उठाने में सक्षम होंगे। यहां तक ​​कि अगर आंतरिक क्वेरी केवल एक इंडेक्स का उपयोग कर सकती है, तो 10,000 पंक्तियां ~ 13 चाहती हैं, जो कुल 13,000 तक गिर जाती है।

exists ऑपरेटर पहली बार पंक्तियों को संसाधित करना बंद कर सकता है, क्वेरी लागत को और अधिक कम कर सकता है, खासकर जब अधिकांश बाहरी पंक्तियां कम से कम एक आंतरिक पंक्ति से मेल खाते हैं।

कुछ दुर्लभ मामलों में, मैंने SQL सर्वर 2008R2 को एक विलय में शामिल होने के लिए सहसंबंधित सबक्वायरी को ऑप्टिमाइज़ किया है (जो केवल एक बार दोनों सेटों को पार करता है - सर्वोत्तम संभव परिदृश्य) जहां एक आंतरिक सूचकांक दोनों आंतरिक और बाहरी प्रश्नों में पाया जा सकता है।

खराब प्रदर्शन के लिए असली अपराधी जरूरी सहसंबद्ध सबक्वेरी, लेकिन नेस्टेड स्कैन नहीं है।

3

यह MySQL संस्करण पर निर्भर करता है - 6.0 तक संस्करणों में MySQL क्वेरी ऑप्टिमाइज़र में एक बग है।

"आईएन" के साथ उप-सामान सही ढंग से अनुकूलित नहीं किए गए थे (लेकिन बार-बार आश्रित लोगों की तरह निष्पादित)। यह बग exists प्रश्नों या जोड़ों को प्रभावित नहीं करता है।

समस्या यह है कि एक बयान एक में सबक्वेरी का उपयोग करता है के लिए, अनुकूलक एक सहसंबद्ध सबक्वेरी के रूप में उसे पुनः लिखता है। निम्नलिखित कथन पर विचार करें जो एक असंबद्ध सबक्वायरी का उपयोग करता है:

चुनें ... टी 1 से जहां t1.a में (टी 2 से बी चुनें);

अनुकूलक एक सहसंबद्ध सबक्वेरी के बयान का पुनर्लेखन:

का चयन करें ... t1 कहां मौजूद है (टी 2 से 1 का चयन करें जहां t2.b = t1.a);

भीतरी और बाहरी प्रश्नों एम और एन पंक्तियों को वापस तो क्रमश: निष्पादन समय (एम × एन), हे के आदेश नहीं बल्कि हे (एम + N) के रूप में की तुलना में यह एक असहसंबद्ध के लिए होगा पर हो जाता है सबक्वेरी।

रेफरी।

+2

'ओ (एमएक्सएन) केस ऐसा नहीं लगता है कि इसे ओपी के लिए सिद्धांत रूप में लागू करना चाहिए क्योंकि सहसंबंधित उप क्वेरी इंडेक्स का उपयोग कर सकती है। MySQL में जब यह आंतरिक असंबद्ध उप क्वेरी का मूल्यांकन करता है तो संभवत: इसे अभी भी इसे कहीं भी स्टोर करना होगा और भौतिक परिणाम को फिर से चलाने के लिए एक नेस्टेड लूप के भीतरी हिस्से में उतना ही होगा? किस मामले में भौतिक परिणाम अनुक्रमित है? या क्या यह हैश जॉइन या यहां कुछ उपयोग करेगा? –

1

जैसा कि आप पहले ही जानते हैं, एक सबक्वायरी बाहरी क्वेरी से मूल्यों का उपयोग नहीं करती है, इस प्रकार इसे केवल एक बार निष्पादित किया जाता है। सहसंबंधित सबक्वायरी सिंक्रनाइज़ होती है, इस प्रकार बाहरी क्वेरी में संसाधित प्रत्येक पंक्ति के लिए इसे निष्पादित किया जाता है।

EXISTS का उपयोग करने का लाभ यह है कि, यदि इसे पूरा माना जाता है, तो कम से कम एक पंक्ति लौटने के बाद सबक्वायरी का निष्पादन बंद हो जाता है। तो, यह एक साधारण सबक्वायरी से तेज हो सकता है। लेकिन यह एक सामान्य नियम नहीं है! सभी आपके द्वारा निष्पादित क्वेरी, क्वेरी ऑप्टिमाइज़र और SQL निष्पादन इंजन संस्करण पर निर्भर करते हैं।

EXISTS का उपयोग करने की अनुशंसा की जाती है जब आपके पास if सशर्त कथन है, क्योंकि यह निश्चित रूप से count से तेज़ है।

आप 4 या 3 प्रश्नों के सरल बेंचमार्क का उपयोग करके वास्तव में दोनों उपक्वियों की तुलना नहीं कर सकते हैं।

आशा है कि यह उपयोगी है!

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