Ich habe eine Tabelle mit 15 Millionen Datensätze mit Namen, E-Mail-Adressen und IPs. Ich muss eine andere Spalte in der gleichen Tabelle mit dem Ländercode mit der IP-Adresse aktualisieren. Ich habe eine kleine Datenbank heruntergeladen (ip2location lite - https://lite.ip2location.com/), die alle IP-Bereiche und assoziierte Länder enthält. Die Tabelle ip2location hat folgende Struktur;So optimieren Sie diese Bereich Abfrage
CREATE TABLE `ip2location_db1` (
`ip_from` int(10) unsigned DEFAULT NULL,
`ip_to` int(10) unsigned DEFAULT NULL,
`country_code` char(2) COLLATE utf8_bin DEFAULT NULL,
`country_name` varchar(64) COLLATE utf8_bin DEFAULT NULL,
KEY `idx_ip_from` (`ip_from`),
KEY `idx_ip_to` (`ip_to`),
KEY `idx_ip_from_to` (`ip_from`,`ip_to`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin
Ich verwende die folgende Funktion, um den Ländercode von einer IP-Adresse abzurufen;
CREATE DEFINER=`root`@`localhost` FUNCTION `get_country_code`(
ipAddress varchar(30)
) RETURNS VARCHAR(2)
DETERMINISTIC
BEGIN
DECLARE ipNumber INT UNSIGNED;
DECLARE countryCode varchar(2);
SET ipNumber = SUBSTRING_INDEX(ipAddress, '.', 1) * 16777216;
SET ipNumber = ipNumber + (SUBSTRING_INDEX(SUBSTRING_INDEX(ipAddress, '.', 2),'.',-1) * 65536);
SET ipNumber = ipNumber + (SUBSTRING_INDEX(SUBSTRING_INDEX(ipAddress, '.', -2),'.',1) * 256);
SET ipNumber = ipNumber + SUBSTRING_INDEX(ipAddress, '.', -1);
SET countryCode =
(SELECT country_code
FROM ip2location.ip2location_db1
USE INDEX (idx_ip_from_to)
WHERE ipNumber >= ip2location.ip2location_db1.ip_from AND ipNumber <= ip2location.ip2location_db1.ip_to
LIMIT 1);
RETURN countryCode;
END$$
DELIMITER ;
Ich habe eine EXPLAIN-Anweisung ausgeführt und dies ist die Ausgabe;
'1', 'SIMPLE', 'ip2location_db1', NULL, 'range', 'idx_ip_from_to', 'idx_ip_from_to', '5', NULL, '1', '33.33', 'Using index condition'
Mein Problem ist, dass die Abfrage auf 1000 Datensätze ~ 15s nimmt auszuführen, welche die gleiche Abfrage auf alle die Datenbank bedeuten laufen würde mehr als 2 Tage benötigen, um abzuschließen. Gibt es eine Möglichkeit, diese Abfrage zu verbessern?
PS - Wenn ich den USE INDEX (idx_ip_from_to) entfernen, dauert die Abfrage doppelt so lange. Kannst du erklären warum?
Auch ich bin kein Datenbankexperte so mit mir tragen :)
Hat die Tabelle überlappende Bereiche? Wenn ja, können Sie es nicht optimieren (sogar mit Gordons Vorschlag). –
Verwenden Sie nicht 'utf8' für' country_code' - es dauert 6 Bytes, wenn Sie nur 2 benötigen; benutze 'ascii'. –
Was ist mit IPv6? –