इस दृष्टिकोण में कुछ मापनीयता मुद्दे हैं (क्या आपको शहर-विशिष्ट जियोआईपी डेटा में स्थानांतरित करना चुनना चाहिए), लेकिन डेटा के दिए गए आकार के लिए, यह काफी अनुकूलन प्रदान करेगा।
आप जिस समस्या का सामना कर रहे हैं वह प्रभावी रूप से यह है कि MySQL श्रेणी-आधारित प्रश्नों को बहुत अच्छी तरह से अनुकूलित नहीं करता है। आदर्श रूप से आप "इससे अधिक" के बजाय किसी अनुक्रमणिका पर एक सटीक ("=") लुक-अप करना चाहते हैं, इसलिए हमें आपके पास उपलब्ध डेटा से उस तरह की एक अनुक्रमणिका बनाने की आवश्यकता होगी। इस तरह MySQL के पास मैच की तलाश करते समय मूल्यांकन करने के लिए बहुत कम पंक्तियाँ होंगी।
ऐसा करने के लिए, मेरा सुझाव है कि आप एक लुक-अप तालिका बनाएं जो आईपी पतों के पहले ऑक्टेट (1.2.3.4 से 1.2.3.4) के आधार पर भौगोलिक स्थान तालिका को अनुक्रमित करती है। विचार यह है कि प्रत्येक लुक-अप के लिए आपको करना होगा, आप उन सभी भौगोलिक स्थान आईपी को अनदेखा कर सकते हैं जो आपके द्वारा खोजे जा रहे आईपी के समान ऑक्टेट से शुरू नहीं होते हैं।
CREATE TABLE `ip_geolocation_lookup` (
`first_octet` int(10) unsigned NOT NULL DEFAULT '0',
`ip_numeric_start` int(10) unsigned NOT NULL DEFAULT '0',
`ip_numeric_end` int(10) unsigned NOT NULL DEFAULT '0',
KEY `first_octet` (`first_octet`,`ip_numeric_start`,`ip_numeric_end`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
इसके बाद, हमें आपकी भौगोलिक स्थान तालिका में उपलब्ध डेटा लेने और सभी . को कवर करने वाला डेटा तैयार करने की आवश्यकता है (पहला) भौगोलिक स्थान पंक्ति कवर को अष्टक करता है:यदि आपके पास ip_start = '5.3.0.0'
के साथ कोई प्रविष्टि है और ip_end = '8.16.0.0'
, लुकअप तालिका को ऑक्टेट 5, 6, 7, और 8 के लिए पंक्तियों की आवश्यकता होगी। तो...
ip_geolocation
|ip_start |ip_end |ip_numeric_start|ip_numeric_end|
|72.255.119.248 |74.3.127.255 |1224701944 |1241743359 |
में परिवर्तित होना चाहिए:
ip_geolocation_lookup
|first_octet|ip_numeric_start|ip_numeric_end|
|72 |1224701944 |1241743359 |
|73 |1224701944 |1241743359 |
|74 |1224701944 |1241743359 |
चूंकि यहां किसी ने मूल MySQL समाधान के लिए अनुरोध किया है, यहां एक संग्रहीत कार्यविधि है जो आपके लिए वह डेटा जेनरेट करेगी:
DROP PROCEDURE IF EXISTS recalculate_ip_geolocation_lookup;
CREATE PROCEDURE recalculate_ip_geolocation_lookup()
BEGIN
DECLARE i INT DEFAULT 0;
DELETE FROM ip_geolocation_lookup;
WHILE i < 256 DO
INSERT INTO ip_geolocation_lookup (first_octet, ip_numeric_start, ip_numeric_end)
SELECT i, ip_numeric_start, ip_numeric_end FROM ip_geolocation WHERE
( ip_numeric_start & 0xFF000000 ) >> 24 <= i AND
( ip_numeric_end & 0xFF000000 ) >> 24 >= i;
SET i = i + 1;
END WHILE;
END;
और फिर आपको उस संग्रहीत कार्यविधि को कॉल करके तालिका को पॉप्युलेट करना होगा:
CALL recalculate_ip_geolocation_lookup();
इस बिंदु पर आप अपने द्वारा अभी बनाई गई प्रक्रिया को हटा सकते हैं -- अब इसकी आवश्यकता नहीं है, जब तक कि आप लुक-अप तालिका की पुनर्गणना नहीं करना चाहते।
लुक-अप तालिका के स्थान पर होने के बाद, आपको बस इसे अपने प्रश्नों में एकीकृत करना है और सुनिश्चित करना है कि आप पहले ऑक्टेट द्वारा क्वेरी कर रहे हैं। लुक-अप तालिका के लिए आपकी क्वेरी दो शर्तों को पूरा करेगी:
- उन सभी पंक्तियों को खोजें जो आपके आईपी पते के पहले ऑक्टेट से मेल खाती हों
- उस सबसेट का :वह पंक्ति ढूंढें जिसमें वह श्रेणी हो जो आपके आईपी पते से मेल खाती हो
चूंकि चरण दो डेटा के सबसेट पर किया जाता है, यह संपूर्ण डेटा पर श्रेणी परीक्षण करने से काफी तेज है। यह इस अनुकूलन रणनीति की कुंजी है।
आईपी पते का पहला ऑक्टेट क्या है, यह पता लगाने के कई तरीके हैं; मैंने इस्तेमाल किया ( r.ip_numeric & 0xFF000000 ) >> 24
चूंकि मेरे स्रोत आईपी संख्यात्मक रूप में हैं:
SELECT
r.*,
g.country_code
FROM
ip_geolocation g,
ip_geolocation_lookup l,
ip_random r
WHERE
l.first_octet = ( r.ip_numeric & 0xFF000000 ) >> 24 AND
l.ip_numeric_start <= r.ip_numeric AND
l.ip_numeric_end >= r.ip_numeric AND
g.ip_numeric_start = l.ip_numeric_start;
अब, माना जाता है कि मैं अंत में थोड़ा आलसी हो गया था:आप आसानी से ip_geolocation
से छुटकारा पा सकते थे तालिका पूरी तरह से अगर आपने ip_geolocation_lookup
. बनाया है तालिका में देश का डेटा भी होता है। मुझे लगता है कि इस क्वेरी से एक टेबल छोड़ने से यह थोड़ा तेज हो जाएगा।
और, अंत में, यहाँ दो अन्य तालिकाएँ हैं जिनका उपयोग मैंने संदर्भ के लिए इस प्रतिक्रिया में किया है, क्योंकि वे आपकी तालिकाओं से भिन्न हैं। मुझे यकीन है कि वे संगत हैं, हालांकि।
# This table contains the original geolocation data
CREATE TABLE `ip_geolocation` (
`ip_start` varchar(16) NOT NULL DEFAULT '',
`ip_end` varchar(16) NOT NULL DEFAULT '',
`ip_numeric_start` int(10) unsigned NOT NULL DEFAULT '0',
`ip_numeric_end` int(10) unsigned NOT NULL DEFAULT '0',
`country_code` varchar(3) NOT NULL DEFAULT '',
`country_name` varchar(64) NOT NULL DEFAULT '',
PRIMARY KEY (`ip_numeric_start`),
KEY `country_code` (`country_code`),
KEY `ip_start` (`ip_start`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
# This table simply holds random IP data that can be used for testing
CREATE TABLE `ip_random` (
`ip` varchar(16) NOT NULL DEFAULT '',
`ip_numeric` int(10) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`ip`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;