我尝试使用空间索引。 我有一个IP表,以及一个具有IP块范围的ip2geo表。 我正在尝试从ip2geo表为每个IP分配地理位置ID。
当尝试使用列值进行选择时,空间索引没有被使用。
EXPLAIN
SELECT *,
( SELECT locid FROM `ipblocks` i
WHERE MBRCONTAINS(i.ippolygon,
POINTFROMWKB(POINT(h.`ip`, 0))) ) AS locaid
FROM `ips` h LIMIT 1;
id select_type table type possible_keys key key_len ref rows Extra 1 主查询 h 全部 无 无 无 无 33279 2 DEPENDENT 子查询 i 全部 ipblock_spatialidx 无 无 无 4977388 使用where条件
当在过滤器中使用常量时,会使用索引。
EXPLAIN SELECT *,(SELECT locid FROM `ipblocks` i WHERE
MBRCONTAINS(i.ippolygon, POINTFROMWKB(POINT(3223394542, 0))) ) AS
locaid FROM `ips` h LIMIT 1;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY h ALL NULL NULL NULL NULL 33279 Using filesort 2 UNCACHEABLE
SUBQUERY i range ipblock_spatialidx ipblock_spatialidx 34 NULL 1 Using where
当进行内连接时,索引会被使用(检查额外信息)
EXPLAIN SELECT * FROM `ips` h INNER JOIN `ipblocks` i ON (MBRCONTAINS(i.ippolygon, POINTFROMWKB(POINT(h.`cp`, 0)))) LIMIT 100 ;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE h ALL NULL NULL NULL NULL 33279
1 SIMPLE i ALL ipblock_spatialidx NULL NULL NULL 4977388
每个记录都进行范围检查(索引映射:0x1)
在左连接时,不使用索引。
EXPLAIN SELECT * FROM `ips` h LEFT JOIN `ipblocks` i ON (MBRCONTAINS(i.ippolygon, POINTFROMWKB(POINT(h.`ip`, 0)))) LIMIT 100 ;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE h ALL NULL NULL NULL NULL 33279
1 SIMPLE i ALL ipblock_spatialidx NULL NULL NULL 4977388
如何优化我的SQL查询以使用空间索引?
更新:
我能够通过使用插入触发器快速分配GEO国家。但是我仍然需要知道为什么在连接或子查询时无法使用空间索引。
BEGIN
DECLARE geoloc VARCHAR(10) DEFAULT NULL;
SELECT country FROM ipblocks i LEFT JOIN iplocations l ON(i.locid=l.locid) WHERE MBRCONTAINS(i.ippolygon, POINTFROMWKB(POINT(NEW.ip, 0))) LIMIT 1 INTO geoloc;
SET NEW.geo= geoloc;
END
更新2:对@John的问题
我的目标是使用以下模式获取表IPs
username, ipaddress, country
我购买了一张带有IP范围的GEO2IP表格,使用它生成一个INET_ANOT()表格 IPblocks
ipfrom,ipto,country,poly [example POLYGON((16777216 -1,16777471 -1,16777471 1,16777216 1,16777216 -1)) ]
如何使用ipblocks
的地理空间索引来更新表IPs
中的国家,而不需要创建触发器或存储过程?
最后一个更新(承诺)使用的解决方案。
SELECT * FROM `iplist` i LEFT JOIN `iplocations` l ON (SELECT GetLocId(INET_ATON(i.`ip`))=l.`locid`) ;
GetLocId使用以下SQL语句
SELECT locid FROM `ipblocks` i WHERE
MBRCONTAINS(i.ippolygon, POINTFROMWKB(POINT(@INPUTVAR, 0))) INTO locid
并返回locid,它在39ms内匹配了40k个ip地址