मैं इसी तरह के मुद्दे से निपट रहा था, जहां मुझे लगभग 4 मिलियन आईपी श्रेणियों के साथ एक डेटाबेस खोजना पड़ा और एक अच्छा समाधान मिला जिसने स्कैन की गई पंक्तियों की संख्या को 4 मिलियन से घटाकर ~ 5 (आईपी के आधार पर) कर दिया:पी>
यह SQL कथन:
SELECT id FROM geoip WHERE $iplong BETWEEN range_begin AND range_end
में बदल दिया जाता है:
SELECT id FROM geoip WHERE range_begin <= $iplong AND range_end >= $iplong
मुद्दा यह है कि MySQL 'range_begin <=$iplong' के साथ सभी पंक्तियों को पुनः प्राप्त करता है और फिर स्कैन करने की आवश्यकता होती है यदि 'range_end>=$iplong'। यह पहली AND शर्त (range_begin <=$iplong) ने लगभग 2 मिलियन पंक्तियों को पुनः प्राप्त किया, और अगर रेंज_एंड मेल खाती है तो सभी की जाँच की जानी चाहिए।
हालांकि इसे एक और शर्त जोड़कर नाटकीय रूप से सरल बनाया जा सकता है:
SELECT id FROM geoip WHERE range_begin <= $iplong AND range_begin >= $iplong-65535 AND range_end >= $iplong
बयान
range_begin <= $iplong AND range_begin >= $iplong-65535
केवल वही प्रविष्टियाँ प्राप्त करता है जहाँ range_begin $iplong-65535 और $iplong के बीच है। मेरे मामले में, इसने 4 Mio से पुनर्प्राप्त पंक्तियों की संख्या कम कर दी। लगभग 5 तक और स्क्रिप्ट रनटाइम कई मिनटों से कुछ सेकंड के लिए नीचे चला गया।
65535 पर ध्यान दें :यह मेरी तालिका के लिए रेंज_बेगिन और रेंज_एंड के बीच की अधिकतम दूरी है, यानी (रेंज_एंड-रेंज_बेगिन) <=65535 मेरी सभी पंक्तियों के लिए। यदि आपके पास बड़ी IP-श्रेणियाँ हैं, तो आपको 65535 को बढ़ाना होगा, यदि आपके पास छोटी IP-श्रेणियाँ हैं, तो आप इस स्थिरांक को कम कर सकते हैं। यदि यह स्थिरांक बहुत बड़ा है (उदाहरण के लिए 4 बिलियन), तो आप कोई क्वेरी समय नहीं बचाएंगे।
इस क्वेरी के लिए, आपको केवल range_begin पर एक अनुक्रमणिका चाहिए।