数据表结构
sql
CREATE TABLE `ip_location` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ip_start` int(11) unsigned NOT NULL,
`ip_end` int(11) unsigned NOT NULL,
`country` varchar(255) NOT NULL DEFAULT '',
`province` varchar(255) NOT NULL DEFAULT '',
`city` varchar(255) NOT NULL DEFAULT '',
`isp` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `idx_ip` (`ip_start`,`ip_end`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
IP 转换函数
sql
IP 转数字
DELIMITER $$
CREATE FUNCTION ip_to_number(ip VARCHAR(15))
RETURNS INT UNSIGNED
READS SQL DATA
DETERMINISTIC
BEGIN
RETURN INET_ATON(ip);
END$$
DELIMITER ;
数字转 IP
DELIMITER $$
CREATE FUNCTION number_to_ip(num INT UNSIGNED)
RETURNS VARCHAR(15)
READS SQL DATA
DETERMINISTIC
BEGIN
RETURN INET_NTOA(num);
END$$
DELIMITER ;
2、查询函数
sql
DELIMITER $$
CREATE FUNCTION get_ip_location(ip_addr VARCHAR(15))
RETURNS TEXT
READS SQL DATA
DETERMINISTIC
BEGIN
DECLARE result TEXT DEFAULT '';
DECLARE ip_num INT UNSIGNED;
SET ip_num = INET_ATON(ip_addr);
SELECT CONCAT(country, '-', province, '-', city, '-', isp)
INTO result
FROM ip_location
WHERE ip_start <= ip_num AND ip_end = ip_num
LIMIT 1;
RETURN IFNULL(result, '未知');
END$$
DELIMITER ;
3、常用查询语句
sql
根据 IP 查询位置信息
SELECT
INET_NTOA(ip_start) as start_ip,
INET_NTOA(ip_end) as end_ip,
country,
province,
city,
isp
FROM ip_location
WHERE ip_start <= INET_ATON('192.168.1.1')
AND ip_end = INET_ATON('192.168.1.1');
批量查询示例
SELECT
visitor_ip,
INET_NTOA(ip_location.ip_start) as location_ip_start,
country,
province,
city
FROM visitor_log v
LEFT JOIN ip_location ON (
INET_ATON(v.visitor_ip) BETWEEN ip_location.ip_start AND ip_location.ip_end
);
4、数据导入脚本
sql
导入 IP 数据(示例)
LOAD DATA INFILE '/path/to/ip_data.txt'
INTO TABLE ip_location
FIELDS TERMINATED BY '\t'
LINES TERMINATED BY '\n'
(ip_start, ip_end, country, province, city, isp);
sql
创建索引
CREATE INDEX idx_ip_range ON ip_location(ip_start, ip_end);
分区表(按IP范围分区)
CREATE TABLE ip_location_partitioned (
id INT AUTO_INCREMENT,
ip_start INT UNSIGNED,
ip_end INT UNSIGNED,
country VARCHAR(255),
province VARCHAR(255),
city VARCHAR(255),
isp VARCHAR(255),
PRIMARY KEY (id, ip_start)
) PARTITION BY RANGE (ip_start) (
PARTITION p0 VALUES LESS THAN (16777216), 1.0.0.0
PARTITION p1 VALUES LESS THAN (33554432), 2.0.0.0
PARTITION p2 VALUES LESS THAN (50331648), 3.0.0.0
PARTITION pmax VALUES LESS THAN MAXVALUE
);