यहाँ क्या हो रहा है।
The SELECT COUNT (...) icd_index where icd='25000'
सूचकांक का उपयोग करेगा, जो डेटा से अलग एक BTree है। लेकिन यह इसे इस तरह से स्कैन करता है:
- आईसीडी='25000' वाली पहली प्रविष्टि खोजें। यह लगभग तात्कालिक है।
- आइसीडी में बदलाव मिलने तक स्कैन करें। यह केवल इंडेक्स में स्कैन करेगा, डेटा को टच नहीं करेगा। EXPLAIN के अनुसार, स्कैन करने के लिए लगभग 910,104 अनुक्रमणिका प्रविष्टियाँ होंगी।
अब आइए उस सूचकांक के लिए BTree को देखें। इंडेक्स में फ़ील्ड के आधार पर, प्रत्येक पंक्ति ठीक 22 बाइट्स होगी, साथ ही कुछ ओवरहेड (अनुमानित 40%) होगा। एक MyISAM इंडेक्स ब्लॉक 1KB (cf InnoDB का 16KB) है। मैं प्रति ब्लॉक 33 पंक्तियों का अनुमान लगाऊंगा। 910,104/33 का कहना है कि COUNT करने के लिए लगभग 27K ब्लॉक को पढ़ने की जरूरत है। (नोट COUNT(core_id)
core_id
check की जांच करने की आवश्यकता है शून्य होने के लिए, COUNT(*)
नहीं करता; यह एक मामूली अंतर है।) एक सादे हार्ड ड्राइव पर 27K ब्लॉक पढ़ने में लगभग 270 सेकंड लगते हैं। आप भाग्यशाली थे कि इसे 60 सेकंड में पूरा कर लिया।
दूसरे रन में उन सभी ब्लॉकों को key_buffer में मिला (यह मानते हुए कि key_buffer_size कम से कम 27MB है), इसलिए उसे डिस्क की प्रतीक्षा नहीं करनी पड़ी। इसलिए यह बहुत तेज था। (यह क्वेरी कैश को अनदेखा कर रहा है, जिसे फ्लश करने या SQL_NO_CACHE का उपयोग करने के लिए आपके पास ज्ञान था।)
5.6 अप्रासंगिक होता है (लेकिन इसका उल्लेख करने के लिए धन्यवाद), क्योंकि यह प्रक्रिया 4.0 या उससे पहले के बाद से नहीं बदली है (सिवाय इसके कि utf8 मौजूद नहीं था; उस पर और नीचे)।
InnoDB पर स्विच करने से कुछ तरीकों से मदद मिलेगी। प्राथमिक कुंजी डेटा के साथ 'क्लस्टर' होगी, एक अलग बीट्री के रूप में संग्रहीत नहीं की जाएगी। इसलिए, एक बार डेटा या पीके कैश हो जाने के बाद, दूसरा तुरंत उपलब्ध हो जाता है। ब्लॉकों की संख्या 5K की तरह अधिक होगी, लेकिन वे 16KB ब्लॉक होंगे। कैश के ठंडे होने पर इन्हें तेजी से लोड किया जा सकता है।
आप पूछते हैं "क्या मुझे अकेले आईसीडी पर एक इंडेक्स की आवश्यकता है?" - ठीक है कि माईसाम बीट्री आकार को प्रति पंक्ति लगभग 21 बाइट तक कम कर देगा, इसलिए बीट्री आकार के बारे में 21/27 वां होगा, ज्यादा सुधार नहीं (कम से कम के लिए कोल्ड-कैश स्थिति)।
एक और विचार है, अगर icd
MEDIUMINT UNSIGNED
. का उपयोग करने के लिए हमेशा संख्यात्मक और हमेशा संख्यात्मक होता है , और ZEROFILL
. से निपटें अगर इसमें अग्रणी शून्य हो सकते हैं।
ओह, मैं CHARACTER SET को नोटिस करने में विफल रहा। (मैंने ऊपर दिए गए नंबर तय कर दिए हैं, लेकिन मुझे विस्तार से बताएं।)
- CHAR(5) 5 वर्णों के लिए अनुमति देता है ।
- ascii को 1 बाइट लगता है प्रति चरित्र ।
- utf8 में 3 बाइट्स तक का समय लगता है प्रति वर्ण ।
- तो, CHAR(5) CHARACTER SET utf8 में 15 बाइट लगते हैं हमेशा ।
कॉलम को CHAR(5) CHARACTER SET ascii
. में बदलना इसे 5 बाइट तक छोटा कर देगा।
इसे MEDIUMINT UNSIGNED ZEROFILL में बदलने से यह 3 बाइट्स तक सिकुड़ जाएगा।
डेटा को सिकोड़ने से I/O में लगभग समानुपातिक मात्रा में तेजी आएगी (अन्य दो क्षेत्रों के लिए अन्य 6 बाइट्स की अनुमति देने के बाद।