2012-12-31 10 views
7
explain 
select 
    * 
from 
    zipcode_distances z 
inner join 
    venues v  
    on z.zipcode_to=v.zipcode 
inner join 
    events e 
    on v.id=e.venue_id 
where 
    z.zipcode_from='92108' and 
    z.distance <= 5 

मैं ज़ीपोड 92108 के 5 मील के भीतर स्थानों पर सभी "घटनाओं को खोजने की कोशिश कर रहा हूं", हालांकि, मुझे इस क्वेरी को अनुकूलित करने में कठिनाई हो रही है।मैं इस mysql क्वेरी पर पूर्ण तालिका स्कैन से कैसे बच सकता हूं?

id, select_type, table, type, possible_keys, key, key_len, ref, rows, Extra 

1, SIMPLE, e, ALL, idx_venue_id, , , , 60024, 
1, SIMPLE, v, eq_ref, PRIMARY,idx_zipcode, PRIMARY, 4, comedyworld.e.venue_id, 1, 
1, SIMPLE, z, ref, idx_zip_from_distance,idx_zip_to_distance,idx_zip_from_to, idx_zip_from_to, 30, const,comedyworld.v.zipcode, 1, Using where; Using index 

मैं "ई" मेज पर एक पूर्ण तालिका स्कैन हो रही है, और मैं समझ नहीं क्या सूचकांक मैं इसे पाने के लिए बनाने की जरूरत:

यहाँ कैसी लगती है समझाने है तेज़ होना

किसी भी सलाह की सराहना की जाएगी

धन्यवाद

+0

क्या आपको परिणाम सेट में सभी तालिकाओं से सभी कॉलम चाहिए? –

+0

मैं "इन" उपखंड का उपयोग करने से बचने की कोशिश कर रहा हूं। – john

+0

जो मैं करने की कोशिश कर रहा हूं उसका समेकित विवरण उन स्थानों को ढूंढना है जिनके ज़िपकोड्स ज़िपोड्स में रहते हैं जो मुझे 92108 के निकटता में पाया जाता है। इसलिए यह स्थल पर शामिल हो जाता है, और फिर उस स्थान से जुड़ी घटनाओं में शामिल होता है । – john

उत्तर

7

अपने प्रश्न में EXPLAIN उत्पादन के आधार पर, आप पहले से ही सभी अनुक्रमित है क्वेरी का उपयोग करना चाहिए, अर्थात्:

CREATE INDEX idx_zip_from_distance 
    ON zipcode_distances (zipcode_from, distance, zipcode_to); 
CREATE INDEX idx_zipcode ON venues (zipcode, id); 
CREATE INDEX idx_venue_id ON events (venue_id); 

(मैं अपने सूचकांक के नाम से यकीन नहीं है कि वास्तव में idx_zip_from_distance शामिल नहीं कर रहा हूँ zipcode_to कॉलम। यदि नहीं, तो आपको इसे covering index बनाने के लिए जोड़ना चाहिए। इसके अलावा, मैंने कॉलम idx_zipcode में पूर्णता के लिए शामिल किया है, लेकिन, यह मानते हुए कि यह तालिका के लिए प्राथमिक कुंजी है और आप इनो डीबी का उपयोग कर रहे हैं, वैसे भी स्वचालित रूप से शामिल किया जाएगा।)

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

एक कारण यह सच है कि आप भी कई अनुक्रमित जो योजनाकार भ्रमित कर रहे हैं कि हो सकता है। उदाहरण के लिए, क्या आप वास्तव में को उन सभी तीन इंडेक्स को ज़िपकोड टेबल पर चाहिए, बशर्ते कि यह संग्रहीत डेटा संभवतः सममित है? निजी तौर पर, मैं ऊपर वर्णित इंडेक्स का सुझाव देता हूं, साथ ही (zipcode_to, zipcode_from) पर एक अनन्य इंडेक्स (जो कि आपके पास कृत्रिम नहीं है) (एक प्राथमिक सूचकांक भी हो सकता है) (अधिमानतः उस क्रम में, ताकि किसी भी प्रासंगिक प्रश्न पर zipcode_to=? इसका उपयोग कर सकते हैं)।

हालांकि, मैंने कुछ परीक्षणों के आधार पर, मुझे मुख्य मुद्दा पर संदेह है कि क्यों MySQL गलत क्वेरी प्लान चुन रहा है, बस आपकी तालिकाओं की सापेक्ष कार्डिनिटी पर आता है। संभवतः, आपकी वास्तविक zipcode_distances तालिका विशाल है, और MySQL पर्याप्त समझ में नहीं आता है कि WHERE खंड में स्थितियों में वास्तव में यह कितना संकीर्ण है।

हां, तो सबसे अच्छा और सरल ठीक बस force MySQL to use the indexes you want हो सकता है: कि क्वेरी के साथ

select 
    * 
from 
    zipcode_distances z 
    FORCE INDEX (idx_zip_from_distance) 
inner join 
    venues v  
    FORCE INDEX (idx_zipcode) 
    on z.zipcode_to=v.zipcode 
inner join 
    events e 
    FORCE INDEX (idx_venue_id) 
    on v.id=e.venue_id 
where 
    z.zipcode_from='92108' and 
    z.distance <= 5 

, आप वास्तव में वांछित क्वेरी योजना मिलना चाहिए। (आप यहाँ क्या ज़रूरत है FORCE INDEX, बस USE INDEX साथ के बाद से क्वेरी योजनाकार अभी भी एक मेज सुझाव सूचकांक के बजाय स्कैन उपयोग करने का निर्णय कर सकता है, उद्देश्य को पराजित किया। मैं इस हो सकता है जब मैं पहली बार इस परीक्षण किया था।)

Ps। एसक्यूएलआईज़ पर एक डेमो है, इस मुद्दे का प्रदर्शन करते हुए with और withoutFORCE INDEX दोनों।

0

आप एक सबक्वेरी इस्तेमाल कर सकते हैं:

select * from zipcode_distances z, venues v, events e 
where 
    z.id in (select id from zipcode z where z.zipcode_from='92108' and z.distance <= 5) 
    and z.zipcode_to=v.zipcode 
    and v.id=e.venue_id 
1

दोनों तालिकाओं में स्तंभों अनुक्रमित है?

e.id and v.venue_id 

यदि आप नहीं करते हैं, तो दोनों तालिकाओं में अनुक्रमणिका बनाते हैं। यदि आपके पास पहले से है, तो यह हो सकता है कि आपके पास एक या अधिक तालिकाओं में कुछ रिकॉर्ड हैं और विश्लेषक यह पता लगाता है कि अनुक्रमित पढ़ने के बजाय पूर्ण स्कैन करने के लिए यह अधिक कुशल है।

0

आप सभी टेबल (select *) से सभी कॉलम का चयन कर रहे हैं, इसलिए एक इंडेक्स का उपयोग करके ऑप्टिमाइज़र में थोड़ा सा बिंदु है जब क्वेरी इंजन को इंडेक्स से प्रत्येक पंक्ति पर तालिका में लुकअप करना होगा।

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