我有一个mySQL查询,需要很长时间才能处理。我正在查询与国家/地区代码相关的大范围IP表,以便在url_click表中发现每个IP的原始国家/地区。 (来自hxxp的IP数据库://ip-to-country.webhosting.info/)
虽然很慢,但效果非常好。
有没有更有效的方法来编写此查询?
表格和输出JPG:http://tiny.cx/a4e00d
SELECT ip_addr AS IP, geo_ip.ctry, count(ip_addr) as count
FROM `admin_adfly`.`url_click`,admin_adfly.geo_ip
WHERE INET_ATON (ip_addr)
BETWEEN geo_ip.ipfrom AND geo_ip.ipto
AND url_id = 165
GROUP BY ip_addr;
答案 0 :(得分:0)
IP地址具有树状结构,并且geo_ip表中的范围很可能与该结构相符。
如果您的IP以193.167开头,那么您应该有一个索引可以帮助您快速过滤geo_ip表,以便只处理与193.167子范围相关的行。
我认为你应该能够通过这种方法显着改善响应时间。
我希望这会对你有所帮助
答案 1 :(得分:0)
那INET_ATON
让我有点担心。它会使ip_addr
列上的任何索引无效。如果您有一种方法可以将信息全部放在相同的格式中,比如在将数据放入数据库之前将数据转换为数字,这可能会有所帮助。
除此之外,有关明智使用索引的标准建议适用。您可能希望在ipfrom
和ipto
和/或url_id
列上建立索引。
答案 2 :(得分:0)
MySQL
不会优化此类查询。
您需要将ipfrom-ipto
范围转换为LineStrings
,从而允许在其上构建R-Tree
索引:
ALTER TABLE
geo_ip
ADD range LINESTRING;
UPDATE geo_ip
SET range = LINESTRING(POINT(-1, ipfrom), POINT(1, ipfrom));
ALTER TABLE
geo_ip
MODIFY range LINESTRING NOT NULL;
CREATE SPATIAL INDEX
sx_geoip_range
ON geo_ip (range);
SELECT ip_addr AS IP, geo_ip.ctry, COUNT(*)
FROM `admin_adfly`.`url_click`
JOIN admin_adfly.geo_ip
ON MBRContains
(
Point(0, INET_ATON (ip_addr)),
range
)
WHERE url_id = 165
GROUP BY
ip_addr
geo_ip
应为MyISAM
表。
请点击此处了解更多详情:
答案 3 :(得分:0)
在两个表之间的连接中使用函数将比正常连接慢,因此您可能希望尽可能延迟该特定操作。所以,我总结了数据,然后加入它:
SELECT S.IP_Addr, G.Ctry AS Country, S.Count
FROM (SELECT ip_addr, COUNT(ip_addr) AS Count
FROM admin_adfly.url_click
WHERE url_id = 165
GROUP BY ip_addr) AS S
JOIN admin_adfly.geo_ip AS G
ON INET_ATON (ip_addr) BETWEEN geo_ip.ipfrom AND geo_ip.ipto;
如果您可以重新设计架构并且将要进行大量此分析,请重新编写两个表中的一个,以便连接条件不需要使用INET_ATON()。
据推测,您在url_id
列上有一个索引;这是唯一一个能给你带来很多好处的东西。