2012-03-01 20 views
9

मेरे पास एक प्रश्न है जो मुझे समस्याएं दे रहा है और मुझे समझ में नहीं आ रहा है कि क्यों MySQL का क्वेरी ऑप्टिमाइज़र इस तरह से व्यवहार कर रहा है। यहां पृष्ठभूमि की जानकारी दी गई है:MySQL इस क्वेरी को अनुकूलित क्यों नहीं कर सकता?

मेरे पास 3 टेबल हैं। दो अपेक्षाकृत छोटे हैं और एक बड़ा है।

तालिका 1 (बहुत छोटे, 727 पंक्तियाँ):

CREATE TABLE ipa (
ipa_id पूर्णांक (11) नहीं NULL AUTO_INCREMENT,
ipa_code पूर्णांक (11) डिफ़ॉल्ट शून्य,
ipa_name varchar (100) डिफ़ॉल्ट शून्य,
payorcode varchar (2) डिफ़ॉल्ट शून्य,
compid पूर्णांक (11) डिफ़ॉल्ट '2'
प्राथमिक कुंजी (ipa_id),
कुंजी ipa_code (ipa_code)) इंजन = MyISAM

तालिका 2 (छोटा सा, 59,455 पंक्तियों):

CREATE TABLE assign_ipa (
assignid पूर्णांक (11) न्यूल ऑटोमेशन,
ipa_id int (11) न्यूल,
userid int (11) एनयूएल नहीं एल,
username varchar (20) डिफ़ॉल्ट शून्य,
compid पूर्णांक (11) डिफ़ॉल्ट शून्य,
PayorCode चार (10) डिफ़ॉल्ट शून्य
प्राथमिक कुंजी (assignid),
अद्वितीय कुंजी assignid (assignid, ipa_id),
कुंजी ipa_id (ipa_id)
) इंजन = MyISAM

तालिका 3 (बड़े, 24,711,730 पंक्तियाँ):

टेबल बनाएं master_final (
IPA पूर्णांक (11) डिफ़ॉल्ट शून्य,
MbrCt SMALLINT (6) डिफ़ॉल्ट '0',
PayorCode varchar (4) डिफ़ॉल्ट 'शौचालय',
कुंजी idx_IPA (IPA)
) इंजन = MyISAM डिफ़ॉल्ट

क्वेरी के लिए अब

। मैं पहली दो छोटी तालिकाओं का उपयोग करके 3-तरफा जुड़ रहा हूं ताकि अनिवार्य रूप से बड़ी तालिका को इसके अनुक्रमित मानों में से एक पर सब्सक्राइब कर सकूं। असल में, मुझे उपयोगकर्ता, एसजेओनेस के लिए आईडी की एक सूची मिलती है और उन आईडी के लिए बड़ी फ़ाइल से पूछताछ होती है।

mysql>
बताएं मास्टर_फिनल।PayorCode, योग (master_final.Mbrct) MbrCt
रूप से master_final
अंदरूनी ipa.ipa_code पर आईपीए शामिल हों = master_final.IPA
अंदरूनी पर ipa.ipa_id = assign_ipa.ipa_id
assign_ipa शामिल हों जहां assign_ipa.username = 'SJones'
ग्रुप द्वारा master_final.PayorCode, master_final.ipa \ G;
* ** * ** * ** * ** * 1. पंक्ति * ** * ** * ** * * * *
आईडी: 1
select_type: SIMPLE
तालिका: master_final
के प्रकार: सभी
possible_keys: idx_IPA
कुंजी: शून्य
key_len: शून्य
रेफरी: शून्य
पंक्तियों:
अतिरिक्त: अस्थायी का उपयोग करना; filesort
का उपयोग * ** * ** * ** * ** * 2. पंक्ति * ** * ** * ** * ** *
आईडी: 1
SELECT_TYPE: सरल +०१२३८००७३१६ तालिका: आईपीए
प्रकार: रेफरी
possible_keys: प्राथमिक, ipa_code
कुंजी: ipa_code
key_len: 5
रेफरी: wc_test.master_final.IPA
पंक्तियों: 1
अतिरिक्त: जहां
का उपयोग करना * ** * ** * ** * ** * 3।पंक्ति * ** * ** * ** * ** *
आईडी: 1
SELECT_TYPE: सरल
तालिका: assign_ipa
प्रकार: रेफरी
possible_keys: ipa_id
कुंजी: ipa_id
key_len: 4
रेफरी: wc_test.ipa 37
अतिरिक्त:
पंक्तियों .ipa_id (! 30 मिनट की तरह) का उपयोग करते हुए जहां सेट (0.00 सेकंड) में
3 पंक्तियों

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

समझाने के लिए, यहाँ 'SJones' के साथ जुड़े आईडी हैं:

mysql> का चयन करें उपयोगकर्ता नाम, assign_ipa से जहां उपयोगकर्ता नाम = 'SJones' ipa_id;
+ ---------- + -------- +
| उपयोगकर्ता नाम | ipa_id |
+ ---------- + -------- +
| SJones | 688 |
| SJones | 68 9 |
+ ---------- + -------- +
2 सेट में पंक्तियों (0.02 सेकंड)

अब, मैं ipa_id मूल्यों प्रतिस्थापन क्वेरी पुनर्लेखन कर सकते हैं जहां खंड में उपयोगकर्ता नाम के लिए। मेरे लिए यह मूल क्वेरी के बराबर है। MySQL इसे अलग-अलग देखता है। यदि मैं ऐसा करता हूं, तो अनुकूलक बड़ी तालिका पर इंडेक्स का उपयोग करता है।

mysql> समझाने
चयन master_final.PayorCode, योग (master_final.Mbrct) MbrCt
रूप से master_final
अंदरूनी शामिल हों आईपीए पर ipa.ipa_code = master_final.IPA
अंदरूनी शामिल हों ipa.ipa_id पर assign_ipa = assign_ipa.ipa_id
* जहां'_688 ',' 68 9 ') *
ग्रुप द्वारा master_final.PayorCode, master_final.ipa \ G;
* ** * ** * ** * ** * 1।पंक्ति * ** * ** * ** * ** *
आईडी: 1
SELECT_TYPE: सरल
तालिका: आईपीए
प्रकार: सीमा
possible_keys: प्राथमिक, ipa_code
कुंजी: प्राथमिक
key_len: 4
रेफरी: NULL
पंक्तियां: 2
अतिरिक्त: कहां उपयोग करना; अस्थायी का उपयोग करना; filesort
का उपयोग * ** * ** * ** * ** * 2. पंक्ति * ** * ** * ** * ** *
आईडी: 1
SELECT_TYPE: सरल +०१२३८००७३१६ तालिका: assign_ipa
प्रकार: रेफरी
possible_keys: ipa_id
कुंजी: ipa_id
key_len: 4
रेफरी: wc_test.ipa.ipa_id
पंक्तियों: 37
अतिरिक्त: का प्रयोग जहां
* ** * ** * ** * ** * 3. पंक्ति * ** * ** * ** * ** *
आईडी: 1
SELECT_TYPE: सरल
तालिका: master_final
प्रकार: रेफरी
संभव_की: idx_IPA
कुंजी: idx_IPA
key_len: 5
रेफरी: wc_test.ipa.ipa_code
पंक्तियों:
अतिरिक्त: का प्रयोग जहां सेट में
3 पंक्तियों (0.00 सेकंड)

केवल एक चीज मैं बदल दिया है एक जहां खंड है कि बड़ी मेज भी सीधे हिट नहीं करता है। और फिर भी, अनुकूलक बड़ी तालिका पर इंडेक्स 'idx_IPA' का उपयोग करता है और पूर्ण तालिका स्कैन का अब उपयोग नहीं किया जाता है। इस तरह फिर से लिखा गया सवाल बहुत तेज़ है।

ठीक है, यह बहुत सारी पृष्ठभूमि है। अब मेरा सवाल है। अनुकूलक के लिए जहां खंड महत्वपूर्ण है? या तो जहां खंड छोटे तालिका से सेट एक ही परिणाम लौटाएगा, और फिर भी मैं जिस पर उपयोग करता हूं उसके आधार पर मुझे नाटकीय रूप से अलग-अलग परिणाम मिल रहे हैं। जाहिर है, मैं क्वेरी में सभी संबंधित आईडी को पारित करने की कोशिश करने के बजाय उपयोगकर्ता नाम वाले उपयोगकर्ता का उपयोग करना चाहता हूं। जैसा लिखा है, यह संभव नहीं है?

  1. क्या कोई यह समझा सकता है कि यह क्यों हो रहा है?
  2. पूर्ण तालिका स्कैन से बचने के लिए मैं अपनी क्वेरी को फिर से लिख सकता हूं?

मेरे साथ चिपके रहने के लिए धन्यवाद। मुझे यह एक बहुत लंबा सवाल पता है।

+0

मैंने एक MySQL डेवलपर्स (कुछ समय पहले) द्वारा एक लेख पढ़ा था कि ऑप्टिमाइज़र अभी भी प्रगति पर एक काम था - और फिर वे ओरेकल द्वारा अवशोषित हुए थे। क्या आपने जॉइन में "संकेत" या शायद "assign_ipa.username = 'SJones'" को स्थानांतरित करने का प्रयास किया है? –

उत्तर

4

बिल्कुल सही नहीं है कि मैं सही हूं, लेकिन मुझे लगता है कि निम्नलिखित यहां हो रहा है। यह:

WHERE assign_ipa.username = 'SJones' 

एक अस्थायी तालिका बना सकता है, क्योंकि इसे पूर्ण तालिका स्कैन की आवश्यकता होती है। अस्थायी तालिकाओं में कोई अनुक्रमणिका नहीं होती है, और वे चीजों को धीमा कर देते हैं।

दूसरे मामले

INNER JOIN ipa ON ipa.ipa_code = master_final.IPA 
INNER JOIN assign_ipa ON ipa.ipa_id = assign_ipa.ipa_id 
WHERE assign_ipa.ipa_id in ('688','689') 

दूसरे हाथ पर, इंडेक्सों का शामिल होने जो तेज है के लिए अनुमति देता है। इसके अतिरिक्त, इसे

SELECT .... FROM master_final WHERE IDA IN (688, 689) ... 

और मुझे लगता है कि MySQL भी ऐसा कर रहा है।

असाइन_आईपीए.यूसेनेम पर एक इंडेक्स बनाना मदद कर सकता है।

संपादित

मैं इस समस्या की पुन: कल्पना और अब एक अलग व्याख्या की है।

पाठ्यक्रम का कारण गायब सूचकांक है। इसका मतलब है कि MySQL के पास कोई संकेत नहीं है कि query_ipa पूछताछ का परिणाम कितना बड़ा होगा (MySQL गणना नहीं करता है), इसलिए यह पहले शामिल होने के साथ शुरू होता है, जहां यह कुंजी पर रिले कर सकता है।

यह बताएं कि पंक्ति 2 और 3 बताए गए लॉग हमें बताएं।

और उसके बाद, यह assign_ipa.username द्वारा परिणाम, के रूप में पंक्ति में कहा गया है जो, कोई कुंजी है फिल्टर करने के लिए कोशिश करता है 1.

जैसे ही एक सूचकांक है के रूप में, यह assign_ipa पहले फिल्टर, और बाद में मिलती है , अनुक्रमांक का उपयोग कर।

+0

मैंने assign_ipa.username पर एक अनुक्रमणिका जोड़ा और निश्चित रूप से पर्याप्त, समस्या को ठीक किया। प्रतिभाशाली! मैंने इस बारे में कभी नहीं सोचा होगा। आपके सहयोग के लिए धन्यवाद! – craigm

+0

+1 लेकिन खेद है कि मैं अनजान हूं: यह एक अस्थायी तालिका क्यों बनायेगा? स्कैन के दौरान खोजी गई असाइन_आईपीए से आईडी स्टोर करने के लिए? क्या यह वास्तव में छोटी संख्या में मैचों के लिए अस्थायी तालिका में किया गया है, और क्या यह कुछ है जो मुझे अन्य डीबी (ओरेकल, एसक्यूएल) में चिंता करने की ज़रूरत है? धन्यवाद! – Rup

+0

मुझे ओरेकल और एमएस एसक्यूएल अच्छी तरह से नहीं पता, लेकिन मुझे लगता है कि वे क्वेरी लागत का अनुमान लगाने के लिए टेबल आकारों का उपयोग करने में काफी बेहतर हैं। –

2

यह शायद अपने प्रश्न के लिए एक सीधा जवाब नहीं है, लेकिन यहाँ कुछ चीजें हैं जो आप कर सकते हैं:

  1. भागो ANALYZE_TABLE ... यह तालिका आंकड़े जो क्या अनुकूलक पर काफी प्रभाव पड़ता है अद्यतन करेगा करने का फैसला करेंगे।

  2. यदि आप अभी भी सोचते हैं कि जुड़ने की इच्छा नहीं है तो आप उन्हें (जो आपके मामले में होता है, और इस प्रकार ऑप्टिमाइज़र इंडेक्स का उपयोग नहीं कर रहा है, जैसा कि आप उम्मीद करते हैं), आप STRAIGHT_JOIN ... से उपयोग कर सकते हैं here: "STRAIGHT_JOIN वे किस क्रम में FROM खंड में सूचीबद्ध हैं में तालिकाओं में शामिल होने के लिए मजबूर करता अनुकूलक आप अनुकूलक nonoptimal क्रम में टेबल मिलती है, तो एक प्रश्न में तेजी लाने के लिए इसका उपयोग कर सकते हैं।"

  3. मेरे लिए , "जहां भाग" सही में शामिल होने के लिए कभी-कभी एक अंतर बनाता है और चीजों को गति देता है। उदाहरण के लिए, आप लिख सकते हैं:

...t1 INNER JOIN t2 ON t1.k1 = t2.k2 AND t2.k2=something...

बजाय

...t1 INNER JOIN t2 ON t1.k1 = t2.k2 .... WHERE t2.k2=something...

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

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