किसी विशिष्ट तिथि के साथ पंक्तियों की संख्या की गणना करने के लिए, MySQL को इंडेक्स में उस मान का पता लगाना होता है (जो कि बहुत तेज़ है, आखिरकार इसी के लिए इंडेक्स बनाए जाते हैं) और फिर बाद की प्रविष्टियाँ इंडेक्स की को पढ़ें। उन्हें> जब तक उसे अगली तारीख नहीं मिल जाती। esi
. के डेटाटाइप के आधार पर , यह आपकी 700k पंक्तियों को गिनने के लिए कुछ MB डेटा पढ़ने के बराबर होगा। कुछ एमबी पढ़ने में अधिक समय नहीं लगता है (और वह डेटा पहले से ही बफर पूल में कैश किया जा सकता है, यह इस बात पर निर्भर करता है कि आप कितनी बार इंडेक्स का उपयोग करते हैं)।
इंडेक्स में शामिल नहीं किए गए कॉलम के औसत की गणना करने के लिए, MySQL फिर से, उस तारीख के लिए सभी पंक्तियों को खोजने के लिए इंडेक्स का उपयोग करेगा (पहले जैसा ही)। लेकिन इसके अतिरिक्त, प्रत्येक पंक्ति के लिए, उसे उस पंक्ति के लिए वास्तविक तालिका डेटा पढ़ना पड़ता है, जिसका अर्थ है कि पंक्ति का पता लगाने के लिए प्राथमिक कुंजी का उपयोग करना, कुछ बाइट्स पढ़ना और इसे 700k बार दोहराना है। यह "रैंडम एक्सेस"
बहुत है पहले मामले में अनुक्रमिक पढ़ने की तुलना में धीमा। (यह समस्या से बदतर हो जाता है कि "कुछ बाइट्स" innodb_page_size
(डिफ़ॉल्ट रूप से 16KB), इसलिए आपको count(*)
के लिए "कुछ MB" की तुलना में 700k * 16KB =11GB तक पढ़ना पड़ सकता है; और आपके मेमोरी कॉन्फ़िगरेशन के आधार पर, हो सकता है कि इनमें से कुछ डेटा कैश न हो और डिस्क से पढ़ना पड़े।)
इसका एक समाधान इंडेक्स में सभी उपयोग किए गए कॉलम ("कवरिंग इंडेक्स") को शामिल करना है, उदा। date, 01
. पर एक इंडेक्स बनाएं . तब MySQL को तालिका तक पहुंचने की आवश्यकता नहीं है, और केवल अनुक्रमणिका को पढ़कर, पहली विधि के समान ही आगे बढ़ सकता है। अनुक्रमणिका का आकार थोड़ा बढ़ जाएगा, इसलिए MySQL को "कुछ और MB" पढ़ने की आवश्यकता होगी (और avg
निष्पादित करें -ऑपरेशन), लेकिन यह अभी भी कुछ सेकंड का होना चाहिए।
टिप्पणियों में, आपने उल्लेख किया है कि आपको 24 से अधिक स्तंभों के औसत की गणना करने की आवश्यकता है। अगर आप avg
की गणना करना चाहते हैं एक ही समय में कई कॉलम के लिए, आपको उन सभी पर एक कवरिंग इंडेक्स की आवश्यकता होगी, उदा। date, 01, 02, ..., 24
टेबल एक्सेस को रोकने के लिए। ध्यान रखें कि एक इंडेक्स जिसमें सभी कॉलम होते हैं, उसे टेबल के बराबर स्टोरेज स्पेस की आवश्यकता होती है (और इस तरह के इंडेक्स को बनाने में लंबा समय लगेगा), इसलिए यह इस बात पर निर्भर हो सकता है कि यह क्वेरी कितनी महत्वपूर्ण है यदि यह उन संसाधनों के लायक है।
MySQL-लिमिट 16 कॉलम प्रति इंडेक्स से बचने के लिए
, आप इसे दो अनुक्रमणिका (और दो प्रश्नों) में विभाजित कर सकते हैं। उदाहरण बनाएँ इंडेक्स date, 01, .., 12
और date, 13, .., 24
, फिर उपयोग करें
select * from (select `date`, avg(`01`), ..., avg(`12`)
from mytable where `date` = ...) as part1
cross join (select avg(`13`), ..., avg(`24`)
from mytable where `date` = ...) as part2;
इसे अच्छी तरह से प्रलेखित करना सुनिश्चित करें, क्योंकि इस तरह से क्वेरी लिखने का कोई स्पष्ट कारण नहीं है, लेकिन यह इसके लायक हो सकता है।
यदि आप केवल एक ही कॉलम पर औसत रखते हैं, तो आप 24 अलग-अलग इंडेक्स जोड़ सकते हैं (date, 01
पर) , date, 02
, ...), हालांकि कुल मिलाकर, उन्हें और भी अधिक स्थान की आवश्यकता होगी, लेकिन यह थोड़ा तेज़ हो सकता है (क्योंकि वे व्यक्तिगत रूप से छोटे होते हैं)। लेकिन उपयोग पैटर्न और मेमोरी कॉन्फ़िगरेशन जैसे कारकों के आधार पर बफर पूल अभी भी पूर्ण अनुक्रमणिका का पक्ष ले सकता है, इसलिए आपको इसका परीक्षण करना पड़ सकता है।
date
के बाद से आपकी प्राथमिक कुंजी का हिस्सा है, आप प्राथमिक कुंजी को date, esi
. में बदलने पर भी विचार कर सकते हैं . यदि आप प्राथमिक कुंजी द्वारा दिनांक पाते हैं, तो आपको तालिका डेटा तक पहुँचने के लिए एक अतिरिक्त चरण की आवश्यकता नहीं होगी (जैसा कि आप पहले से ही तालिका तक पहुँचते हैं), इसलिए व्यवहार कवरिंग इंडेक्स के समान होगा। लेकिन यह आपकी तालिका में एक महत्वपूर्ण परिवर्तन है और अन्य सभी प्रश्नों को प्रभावित कर सकता है (उदाहरण के लिए esi
का उपयोग करें) पंक्तियों का पता लगाने के लिए), इसलिए इस पर ध्यान से विचार करना होगा।
जैसा कि आपने उल्लेख किया है, एक अन्य विकल्प एक सारांश तालिका बनाना होगा जहां आप पूर्व-परिकलित मानों को संग्रहीत करते हैं, खासकर यदि आप पिछली तिथियों के लिए पंक्तियों को जोड़ते या संशोधित नहीं करते हैं (या उन्हें ट्रिगर के साथ अप-टू-डेट रख सकते हैं)।