2012-10-17 18 views
6

मेरे पास foo (20 अन्य लोगों के बीच) कॉलम bar, baz और quuxbaz और quux पर इंडेक्स के साथ एक तालिका है। तालिका में ~ 500k पंक्तियां हैं।MAX() 100 गुना आदेश से धीमा क्यों है ... LIMIT 1?

प्रश्नों के लिए निम्नलिखित गति इतनी भिन्न क्यों है? क्वेरी ए 0.3 लेता है, जबकि क्वेरी बी 28s लेता है।

क्वेरी एक

select baz from foo 
    where bar = :bar 
    and quux = (select quux from foo where bar = :bar order by quux desc limit 1) 

के बारे में बताएं

id select_type table type possible_keys key  key_len ref  rows Extra 
1 PRIMARY  foo  ref  quuxIdx   quuxIdx 9  const 2  "Using where" 
2 SUBQUERY foo  index NULL   quuxIdx 9  NULL 1  "Using where" 

क्वेरी बी

select baz from foo 
    where bar = :bar 
    and quux = (select MAX(quux) from foo where bar = :bar) 

के बारे में बताएं

id select_type table type possible_keys key  key_len ref  rows Extra 
1 PRIMARY  foo  ref  quuxIdx   quuxIdx 9  const 2  "Using where" 
2 SUBQUERY foo  ALL  NULL   NULL NULL NULL 448060 "Using where" 

मैं MySQL 5.1.34 का उपयोग करें।

+0

'लीमिट 1' का मतलब है 1 पंक्ति लेना और रोकना, है ना?क्वेरी बी ओ (एन * एम) – jondinham

+2

@PaulDinh लगता है कि दोनों प्रश्न एक ही परिणाम बनाते हैं, संभवतः यह संचालन के क्रम से संबंधित है, पहले मामले में यह दूसरी क्वेरी में परिणाम (तेजी से) से quux और खोज बार द्वारा सॉर्ट किया जाता है। खोज बार (पूरी तालिका की जांच करने की आवश्यकता है) को बिना छेड़छाड़ से और फिर अधिकतम –

+0

@ विकटर ढूंढने के लिए सॉर्ट करें, क्या आप दिखा सकते हैं कि आप foo से चुनिंदा बाज़ समझाएं, जहां बार =: बार और quux = (foo से quux चुनें जहां quux = MAX (quux) और bar =: bar) ' 'foo से चुनें baz समझाएं जहां बार =: बार और quux = (foo से quux का चयन करें जहां quux = MAX (quux) और bar =: bar limit 1)' –

उत्तर

6

आपको (bar, quux) पर एक इंडेक्स जोड़ना चाहिए।

इस अनुक्रमणिका के बिना, MySQL नहीं देख सकता कि क्वेरी को कुशलता से कैसे किया जाए ताकि इसे विभिन्न अक्षम क्वेरी योजनाओं में से चुनना पड़े।

पहले उदाहरण में यह quux अनुक्रमणिका स्कैन करता है और प्रत्येक पंक्ति के लिए, मूल तालिका में bar के संबंधित मान को देखता है। प्रत्येक पंक्ति को जांचने में दो बार लगते हैं, लेकिन यह भाग्यशाली हो जाता है कि bar का सही मान उसके स्कैन की शुरुआत के करीब है और इसलिए यह रुक सकता है। ऐसा इसलिए हो सकता है क्योंकि bar का मान आप अक्सर खोज रहे हैं, इसलिए भाग्यशाली होने का मौका बहुत अधिक है। नतीजतन इसे केवल एक मैच खोजने से पहले कुछ पंक्तियों की जांच करनी पड़ सकती है, भले ही प्रत्येक पंक्ति की जांच करने में दो गुना अधिक समय लगे, तथ्य यह है कि केवल कुछ पंक्तियों की जांच की जाती है, जिससे बड़ी बचत होती है। चूंकि आपके पास bar पर कोई अनुक्रमणिका नहीं है, इसलिए MySQL पहले से नहीं जानता है कि मान :bar अक्सर होता है, इसलिए यह नहीं पता कि यह क्वेरी तेज होगी।

दूसरे उदाहरण में यह एक अलग योजना का उपयोग करता है जहां यह हमेशा पूरी तालिका स्कैन करता है। प्रत्येक पंक्ति को सीधे इंडेक्स के उपयोग के बिना तालिका से पढ़ा जाता है। इसका मतलब है कि प्रत्येक पंक्ति पढ़ी जाती है, लेकिन क्योंकि आपके पास बहुत सारी पंक्तियां हैं, यह कुल मिलाकर धीमी है। यदि :bar पर मिलान की गई पंक्तियों में से कोई भी यह तेज़ क्वेरी प्लान नहीं होगा। लेकिन यदि लगभग 1% पंक्तियों में bar का वांछित मूल्य है, तो उपर्युक्त योजना की तुलना में यह क्वेरी योजना का उपयोग करने के लिए लगभग 100 गुना धीमा होगा। चूंकि आपके पास bar पर कोई अनुक्रमणिका नहीं है, इसलिए MySQL इसे पहले से नहीं जानता है।

आप, साथ ही लापता सूचकांक जोड़ सकता है और फिर दोनों प्रश्नों बहुत तेजी से जाना जाएगा।

+1

ऐसा लगता है कि ओपी ने पूछा कि क्यों उसी परिणाम में नाटकीय अंतर –

+0

है, इसलिए foo से quux का चयन करें जहां quux = MAX (quux) और bar =: bar 'foo से 'MAX (quux) का चयन करें, जहां bar =: bar' अगर quux अनुक्रमित int है और बार पाठ है? –

+0

एनवीएम यह अलग-अलग परिणाम देता है :) –

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