जब मैं कॉलम अनुक्रमणित करता हूं तो यह साइक्लाइट क्वेरी बहुत धीमी क्यों होती है?


14

मेरे पास दो तालिकाओं के साथ एक sqlite डेटाबेस है, प्रत्येक में 50,000 पंक्तियों के साथ (नकली) लोगों के नाम हैं। मैंने यह पता लगाने के लिए एक सरल क्वेरी का निर्माण किया है कि कितने नाम हैं (दिए गए नाम, मध्य प्रारंभिक, उपनाम) जो दोनों तालिकाओं के लिए सामान्य हैं:

select count(*) from fakenames_uk inner join fakenames_usa on fakenames_uk.givenname=fakenames_usa.givenname and fakenames_uk.surname=fakenames_usa.surname and fakenames_uk.middleinitial=fakenames_usa.middleinitial;

जब प्राथमिक कुंजी (इस क्वेरी के लिए अप्रासंगिक) को छोड़कर कोई सूचकांक नहीं होता है, तो यह जल्दी से चलता है:

[james@marlon Downloads] $ time sqlite3 generic_data_no_indexes.sqlite "select count(*) from fakenames_uk inner join fakenames_usa on fakenames_uk.givenname=fakenames_usa.givenname and fakenames_uk.surname=fakenames_usa.surname and fakenames_uk.middleinitial=fakenames_usa.middleinitial;"
131

real    0m0.115s
user    0m0.111s
sys     0m0.004s

लेकिन अगर मैं प्रत्येक तालिका के तीन स्तंभों में अनुक्रमणिका जोड़ता हूं (सभी में छः अनुक्रमित):

CREATE INDEX `idx_uk_givenname` ON `fakenames_uk` (`givenname` )
//etc.

फिर यह धीरे-धीरे दर्द करता है:

[james@marlon Downloads] $ time sqlite3 generic_data.sqlite "select count(*) from fakenames_uk inner join fakenames_usa on fakenames_uk.givenname=fakenames_usa.givenname and fakenames_uk.surname=fakenames_usa.surname and fakenames_uk.middleinitial=fakenames_usa.middleinitial;"
131

real    1m43.102s
user    0m52.397s
sys     0m50.696s

क्या इसका कोई तुक या तर्क है?

यहाँ EXPLAIN QUERY PLANअनुक्रमणिका के बिना संस्करण के लिए परिणाम है :

0|0|0|SCAN TABLE fakenames_uk
0|1|1|SEARCH TABLE fakenames_usa USING AUTOMATIC COVERING INDEX (middleinitial=? AND surname=? AND givenname=?)

यह सूचकांक के साथ है:

0|0|0|SCAN TABLE fakenames_uk
0|1|1|SEARCH TABLE fakenames_usa USING INDEX idx_us_middleinitial (middleinitial=?)

1
आपके अनुक्रमित कवर नहीं कर रहे हैं। ऐसा प्रतीत होता है कि आप प्रत्येक कॉलम को व्यक्तिगत रूप से अनुक्रमित कर रहे हैं। जब आप एक सूचकांक में सभी तीन कॉलम युक्त एक कवर सूचकांक बनाने (क्या होता है middleinitial, surnameऔर givenname)?
Randolph West

@ रैंडो वेस्ट मैं समझता हूं कि आपका क्या मतलब है, लेकिन आप सही शब्दावली का उपयोग नहीं कर रहे हैं: "कवरिंग इंडेक्स" वह है जिसमें कॉलम भी चुने जा रहे हैं। उदाहरण के लिए, क्वेरी के लिए SELECT c FROM t WHERE a=1 AND b=2, इंडेक्स t(a,b,c)कवर कर रहा है लेकिन t(a,b)ऐसा नहीं है। सूचकांकों को कवर करने का लाभ यह है कि पूरे क्वेरी परिणाम को सीधे सूचकांक से बाहर निकाला जा सकता है, जबकि गैर-कवरिंग सूचकांक जल्दी से प्रासंगिक पंक्तियों को ढूंढते हैं लेकिन इसे अभी भी मूल्यों को लेने के लिए मुख्य तालिका डेटा को संदर्भित करना होगा।
आर्थर टैकका

जवाबों:


15

SQLite में, जनों को नेस्टेड लूप जॉइन किया जाता है, अर्थात, डेटाबेस एक टेबल से होकर गुजरता है, और प्रत्येक पंक्ति के लिए, दूसरी तालिका से मेल खाती पंक्तियों को खोजता है।

यदि कोई इंडेक्स है, तो डेटाबेस इंडेक्स में किसी भी मैच को जल्दी से देख सकता है, और फिर किसी अन्य कॉलम के मान प्राप्त करने के लिए संबंधित तालिका पंक्ति पर जाएं।

इस मामले में, तीन संभावित सूचकांक हैं। किसी भी सांख्यिकीय जानकारी के बिना (जो ANALYZE चलाकर बनाई जाएगी ), डेटाबेस I और O को कम करने के लिए सबसे छोटा एक चुनता है। हालांकि, middleinitialसूचकांक बेकार है क्योंकि यह तालिका पंक्तियों की संख्या को कम नहीं करता है जिन्हें लाने की आवश्यकता है; और सूचकांक के माध्यम से अतिरिक्त कदम वास्तव में I / O को बढ़ाता है क्योंकि तालिका पंक्तियों को क्रम में नहीं पढ़ा जाता है, लेकिन यादृच्छिक रूप से।

यदि कोई इंडेक्स नहीं है, तो मेल खाने वाली पंक्तियों की खोज के लिए पहली तालिका की प्रत्येक पंक्ति के लिए दूसरी तालिका के पूर्ण टेबल स्कैन की आवश्यकता होगी। यह इतना बुरा होगा कि डेटाबेस का अनुमान है कि इस क्वेरी के लिए अस्थायी सूचकांक बनाना और फिर उसे छोड़ना सार्थक है। यह अस्थायी ("AUTOMATIC") सूचकांक खोज के लिए उपयोग किए जाने वाले सभी कॉलमों पर बनाया गया है। COUNT (*) ऑपरेशन को किसी अन्य कॉलम से मानों की आवश्यकता नहीं है, इसलिए यह इंडेक्स एक कवरिंग इंडेक्स होता है , जिसका अर्थ है कि वास्तव में इंडेक्स प्रविष्टि के अनुरूप तालिका पंक्ति को देखना आवश्यक नहीं है, जो मुझे और भी बचाता है। / हे।

इस क्वेरी को गति देने के लिए, इस इंडेक्स को स्थायी रूप से बनाएं, ताकि अब अस्थायी रूप से निर्माण करना आवश्यक न हो:

CREATE INDEX uk_all_names ON fakenames_uk(surname, givenname, middleinitial);

EXPLAIN QUERY PLAN
SELECT count(*)
FROM fakenames_uk
JOIN fakenames_usa USING (givenname, middleinitial, surname);

0|0|1|SCAN TABLE fakenames_usa
0|1|0|SEARCH TABLE fakenames_uk USING COVERING INDEX uk_all_names (surname=? AND givenname=? AND middleinitial=?)

इस इंडेक्स की surnameअब आवश्यकता नहीं है क्योंकि इस कॉलम पर किसी भी लुकअप के लिए तीन-कॉलम इंडेक्स का उपयोग किया जा सकता है। यदि आप केवल इस स्तंभ पर लुकअप करेंगे, तो
अनुक्रमणिका givennameउपयोगी हो सकती है।
सूचकांक middleinitialहमेशा बेकार है: एक क्वेरी जो 26 संभावित मानों में से एक को खोजती है वह तेज है यदि यह पूरी तालिका को स्कैन करता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.