我有一个包含名称,电子邮件地址和IP的1500万条记录的表。我需要使用IP地址更新同一个表中国家代码的另一列。我下载了一个包含所有IP范围和相关国家的小型数据库(ip2location lite - https://lite.ip2location.com/)。 ip2location表具有以下结构;如何优化此范围查询
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
我使用以下函数从ip地址检索国家代码;
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 ;
我已经运行了EXPLAIN语句,这是输出;
'1', 'SIMPLE', 'ip2location_db1', NULL, 'range', 'idx_ip_from_to', 'idx_ip_from_to', '5', NULL, '1', '33.33', 'Using index condition'
我的问题是,1000条记录查询采用15S〜执行这意味着运行在所有数据库中的相同的查询将需要超过2天就可以完成。有没有办法来改善这个查询。
PS - 如果我删除了USE INDEX(idx_ip_from_to),查询需要两倍的时间。你能解释为什么吗?
而且我不是一个数据库专家,所以容忍我:)
表格是否有重叠范围?如果是这样,你不能优化它(即使戈登的建议)。 –
不要对'country_code'使用'utf8' - 只需要2个时需要6个字节;使用'ascii'。 –
IPv6怎么样? –