2010-08-11 6 views
17

मुझे पता है कि मैं FORCE INDEX (abc) कीवर्ड का उपयोग करके MySQL क्वेरी को निष्पादित करने का तरीका बदल सकता हूं। लेकिन निष्पादन आदेश बदलने का कोई तरीका है?क्या MySQL निष्पादन आदेश को बल देने का कोई तरीका है?

मेरे क्वेरी इस तरह दिखता है:

SELECT c.* 
FROM table1 a 
INNER JOIN table2 b ON a.id = b.table1_id 
INNER JOIN table3 c ON b.itemid = c.itemid 
WHERE a.itemtype = 1 
    AND a.busy = 1 
    AND b.something = 0 
    AND b.acolumn = 2 
    AND c.itemid = 123456 

मैं हर संबंध/बाधा है कि मैं का उपयोग के लिए एक महत्वपूर्ण है। अगर मैं इस कथन पर समझाता हूं तो मुझे लगता है कि mysql पहले c से पूछताछ शुरू करता है।

id select_type table type 
1  SIMPLE   c  ref 
2  SIMPLE   b  ref 
3  SIMPLE   a  eq_ref 

हालांकि, मैं जानता हूँ कि आदेश a -> b -> c तेजी से किया जाएगा में से क्वेरी (मैं सिद्ध कर दिया है कि) कि वहाँ एक रास्ता एक विशेष क्रम का उपयोग करने के mysql बताने के लिए है?

अद्यतन: इस तरह मुझे पता है कि a -> b -> c तेज है।

उपर्युक्त क्वेरी को पूरा करने और 7 पंक्तियों को वापस करने के लिए 1.9 सेकंड लगते हैं। यदि मैं क्वेरी को

SELECT c.* 
FROM table1 a 
INNER JOIN table2 b ON a.id = b.table1_id 
INNER JOIN table3 c ON b.itemid = c.itemid 
WHERE a.itemtype = 1 
    AND a.busy = 1 
    AND b.something = 0 
    AND b.acolumn = 2 
HAVING c.itemid = 123456 

क्वेरी 0.01 सेकंड में पूर्ण हो जाती है (मुझे 10.000 पंक्तियां प्राप्त करने के बिना)। हालांकि यह एक सुरुचिपूर्ण समाधान नहीं है क्योंकि यह क्वेरी एक सरलीकृत उदाहरण है। असली दुनिया में मैं सी से दूसरे टेबल में शामिल हो गया हूं। चूंकि HAVING एक फ़िल्टर है जो पूरे परिणाम पर निष्पादित किया जाता है, इसका मतलब यह होगा कि मैं कुछ आवर्धन को डीबी से अनावश्यक से अधिक रिकॉर्ड खींचूंगा।

EDIT2: बस कुछ जानकारी:

  • इस क्वेरी में चर हिस्सा c.itemid है। बाकी सब कुछ निश्चित मान हैं जो नहीं बदलते हैं।
  • इंडेक्स सेटअप ठीक हैं और mysql
      ए और बी के बीच
    • मेरे लिए सही लोगों को चुनता है एक 1: n संबंध (सूचकांक प्राथमिक प्रयोग किया जाता है)
    • ख के बीच
    • और सी एक कई कई लोगों के लिए नहीं है संबंध (सूचकांक IDX_ITEMID प्रयोग किया जाता है)

मुद्दा यह है कि mysql तालिका एक क्वेरी करने शुरू कर देना चाहिए और यह रास्ता ग करने के लिए नीचे और नहीं इसका उल्टा है काम करते हैं। उसको प्राप्त करने के लिए कोई भी परिवर्तन।

समाधान: मैं नहीं वास्तव में क्या चाहता था, लेकिन यह काम करने के लिए लगता है:

SELECT c.* 
FROM table1 a 
INNER JOIN table2 b ON a.id = b.table1_id 
INNER JOIN table3 c ON b.itemid = c.itemid 
WHERE a.itemtype = 1 
    AND a.busy = 1 
    AND b.something = 0 
    AND b.acolumn = 2 
    AND c.itemid = 123456 
    AND f.id IN (
     SELECT DISTINCT table2.id FROM table1 
     INNER JOIN table2 ON table1.id = table2.table1_id 
     WHERE table1.itemtype = 1 AND table1.busy = 1) 
+1

आपने कैसे साबित किया है कि 'ए -> बी -> सी' तेज होगा? इसके अलावा, क्या आप अपनी अनुक्रमणिका दिखा सकते हैं? – Unreason

+0

परीक्षण के लिए जो तेज़ी से है, परीक्षण करना मुश्किल हो सकता है कि वास्तव में बड़ी मात्रा में डेटा पूर्व लोड और सामान्य भार को अनुकरण करने के बिना। MySQL को अपना स्वयं का अनुकूलन करने देना अक्सर अच्छा होता है, जो आपके पास जितना अधिक डेटा होता है (और समय के साथ, या एक बार या दो बार विश्लेषण तालिका), और यदि आप समस्याओं में भाग लेते हैं तो केवल सूचकांक को बल देते हैं। हालांकि ऐसी समस्याएं मौजूद हैं; मेरे पास निश्चित रूप से ऐसी स्थितियां थीं जहां MySQL की क्वेरी योजना खतरनाक रूप से खराब थी लेकिन एक निश्चित अनुक्रमणिका को मजबूर करने के बाद और इसलिए आदेश में शामिल होने से यह अच्छा और कुशलतापूर्वक काम करता था। – thomasrutter

+0

@thomasrutter: अगर एक 2-7 सेकंड में MySQL के अनुकूलन परिणाम (लोड पर निर्भर करता है डेटा के/राशि) क्वेरी मैं अपने खुद के अनुकूलन का उपयोग कर के रूप में :) Hammerite सुझाव के अलावा कोई अन्य choise है: STRAIGHT_JOIN जो मैं चाहता करता है और 1 क्वेरी बांधा एक हजार गुणा। –

उत्तर

28

शायद आप STRAIGHT_JOIN उपयोग करने के लिए की जरूरत है।

http://dev.mysql.com/doc/refman/5.0/en/join.html

STRAIGHT_JOIN सिवाय इसके कि बायां तालिका हमेशा सही तालिका से पहले पढ़ने के लिए है, JOIN के समान है। इसका उपयोग उन (कुछ) मामलों के लिए किया जा सकता है जिनके लिए जुड़ने वाले ऑप्टिमाइज़र गलत क्रम में टेबल रखता है।

+2

की तरह अतिरिक्त शर्तें जोड़ा जा 'STRAIGHT_JOIN सिवाय इसके कि बायां तालिका हमेशा सही तालिका से पहले पढ़ा जाता है, में शामिल हों के समान है। इसका उपयोग उन (कुछ) मामलों के लिए किया जा सकता है जिनके लिए जुड़ने वाले अनुकूलक टेबल को गलत क्रम में रखता है। 'यही वही था जो मैं खोज रहा था। अब मेरी व्याख्या 'a -> b -> c' दिखाती है और मुझे SUBSELECT की आवश्यकता नहीं है। –

+0

बहुत अच्छा। अजीब, हालांकि, 'STRAIGHT_JOIN' केवल एक आंतरिक शामिल हो सकता है, न कि बाहरी जुड़ाव। http://forums.mysql.com/read.php?115,565624,565668#msg-565668 व्याख्या करने की कोशिश क्यों करता है (आखिरी पंक्ति), लेकिन यह सही नहीं है। ऑप्टिमाइज़र कुछ 'बाएं जॉइन' के लिए ऑर्डर बदल सकता है और जैसा कि 'एक्सप्लाइन' द्वारा दिखाया गया है, और ऐसा लगता है कि उन लोगों के लिए 'STRAIGHT_JOIN' इलाज नहीं है। – Timo

2

आप

  • में जहां हालत में से कुछ लाना शामिल हों
  • परिचय सबक्वेरी दो तरीके

    में पुनर्लेखन की कोशिश कर सकते भले ही वे आवश्यक नहीं हैं

दोनों चीजें हो सकती हैं योजनाकार सीटी।

जांच करने वाली पहली चीज़, हालांकि, यदि आपका stats अद्यतित है तो होगा।

+1

जॉइन में परिणाम जोड़ने से कुछ भी नहीं बदला, लेकिन मैंने बी में पंक्तियों की मात्रा को कम करने के लिए एक सबक्वायरी शामिल की। निष्पादन योजना अभी भी 'c -> b -> a' दिखाती है लेकिन ऐसा लगता है कि यह काम करता है (मेरे अपडेट किए गए प्रश्न को देखें)। –

+0

जॉइन में कोई शर्त जोड़ना वास्तव में कुछ भी सुधार नहीं करेगा। इसका निरीक्षण करने के लिए, क्वेरी को "विस्तारित समझाएं" के साथ पूर्व-पेंड करें, फिर क्वेरी के बाद "चेतावनियां दिखाएं" जोड़ें। शो चेतावनियां ऑप्टिमाइज़ेशन इंजन द्वारा क्वेरी को "अनुकूलित" के रूप में प्रदर्शित करेंगी। यह सभी जॉइन आवश्यकताओं को निकटतम बाउंड WHERE खंड में ले जाता है ... – Nick

2

आप निष्पादन आदेश मजबूर करने के लिए बल सूचकांक का उपयोग कर सकते हैं, और मुझे लगता है कि पहले किया गया है।

यदि आप इसके बारे में सोचते हैं, तो आमतौर पर केवल एक ही ऑर्डर होता है जिसे आप चुनने वाली किसी भी इंडेक्स में टेबल पूछ सकते हैं।

इस मामले में, यदि आप चाहते हैं कि MySQL a पहले पूछताछ शुरू करें, तो सुनिश्चित करें कि b पर आपके द्वारा लागू इंडेक्स b.table1_id है। MySQL केवल उस अनुक्रमणिका का उपयोग करने में सक्षम होगा अगर यह पहले से ही a पूछताछ कर रहा है।

+0

+1 अच्छा जवाब। – Unreason

+0

@ यूरेनिस, क्यों? उपरोक्त दूसरा उत्तर अच्छा जवाब है। – Pacerier

+1

क्योंकि कुछ मामलों में आप संशोधित नहीं कर सकते मौजूदा मिलती है अभी तक आप बल सूचकांक –

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