2011-07-15 32 views
3

我有一个需要很长时间来处理的mySQL查询。我正在查询与国家/地区代码相关的IP范围大表,以查找url_click表中每个IP的原始国家/地区。 (来自hxxp://ip-to-country.webhosting.info/的IP数据库)我的mySQL查询效率如何?

虽然速度很慢,但它的效果非常出色。

有没有更有效的方法来写这个查询?

表和输出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; 
+1

我可以推荐http://codereview.stackexchange.com这种事情吗? –

+2

我怀疑过滤INET_ATON()列上的结果意味着它必须扫描应用INET_ATON()到'url_id = 165'的所有内容 - 你能否预先写入'INET_ATON()'你的以某种方式解决问题,作为专栏?另外,你有一个关于url_id的索引吗?另外,如果你要求MySQL'查询'查询,你会得到什么? – marnir

+0

谢谢大家。我试过Quassnoi建议创建一个索引,但由于某种原因,我无法创建一个b-tree存储类型。然后我尝试了乔纳森·莱弗勒的建议,这确实为查询减少了几秒钟,但它仍然需要很长时间。我决定在初始记录输入点而不是后期查询中查询与IP相关的国家。 – Damo

回答

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列的索引;这是唯一一个能够给你带来很多好处的人。

0

IP地址具有相同的结构和你有你的geo_ip表最有可能尊重结构范围内的树。

如果您的IP以193.167开头,那么您应该有一个索引帮助您非常快速地过滤geo_ip表,以便仅操纵与193.167子范围相关的行。

我认为你应该能够通过这种方法显着提高响应时间。

我希望这将有助于你

0

INET_ATON我担心只是有点。它会使ip_addr列中的任何索引都无用。如果你有一种将信息全部放入同一格式的方法,比如说在将数据放入数据库之前将其转换为数字,这可能会有所帮助。

除此之外,适用有关合理使用索引的标准建议。您可能需要索引ipfromipto,和/或url_id列。

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表。

在这里看到更多的细节: