MYSQL using a spatial index

I am trying to use a spatial index. I have an ips table and an ip2geo table with ip block ranges. I am trying to assign Geo ID to each ip from ip2geo table

When trying to select using a column value, the Spatial Index is not used.

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 PRIMARY h ALL NULL NULL NULL NULL 33279 2 DEPENDENT
    SUBQUERY i ALL ipblock_spatialidx NULL NULL NULL 4977388 Using where

When using a constant, the filter uses an index.

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

      

When using inner index join (check additionally)

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 

      

The range is marked for each entry (index map: 0x1)

When there is no left join, the index is not used.

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

      

How do I optimize my SQL queries to use a spatial index?

UPDATE:

I was able to quickly assign the GEO country using the insert trigger. But I still need to know why I can't use Spatial index when joining or subquery

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

      

UPDATE 2 Question for @John

My goal is to take a table IPs

with the following schema

username, ipaddress, country

      

And use the GEO2IP table I purchased that comes with IP ranges like INET_ANOT () table IPblocks

ipfrom,ipto,country,poly  [example POLYGON((16777216 -1,16777471 -1,16777471 1,16777216 1,16777216 -1)) ]

      

Now without creating a trigger or stored procedure, how can I update the country in the table IPs

using the geospatial index fromIPblocks

LATEST UPDATE (PROVIDING) USED ​​SOLUTION

SELECT *  FROM `iplist` i  LEFT JOIN `iplocations` l ON (SELECT GetLocId(INET_ATON(i.`ip`))=l.`locid`) ;

      

GetLocId uses the following SQL

SELECT locid FROM  `ipblocks` i  WHERE
MBRCONTAINS(i.ippolygon, POINTFROMWKB(POINT(@INPUTVAR,   0))) INTO locid

      

and returns locid, it matches 40k ips in 39ms

+3


source to share


1 answer


What you are seeing is, unfortunately, a common problem with the way spatial functions are implemented in MySQL and the associated disadvantages with subqueries involving spatial functions.

For the Contains and Intersections functions to work correctly, and the index used requires one of the geometries to be a constant. This does not seem to be documented, although all the examples you will see with MySQL with Intersects / Contains work this way.

So, you cannot write something like this like you could in Oracle Spatial or Postgis,

select a.*, b.* 
from sometable a, someothertable b 
where ST_Intersects(a.geom, b.geom) 
and a.someattribute=... and b.someattribute=...;

      

In such a query, if tables a and b have spatial indexes, they will be used if this is more restrictive than any other attribute you can put in the where clause.



The same goes for self-joins, where you want to find all polygons that intersect with all other polygons in the table based on some attribute, for example

select a.* 
from sometable a, sometable b 
where ST_Intersects(a.geom, b.geom) ....

      

So, in MySQL space, you are forced to have one of the constant geometries.

As with the left, the left join syntax doesn't make much sense spatially (although supported), since you are not really joining a single match attribute, but a two-dimensional contain / intersect operator.

Also, I'm pretty sure your inner join is not using the index if you look at key

and the rows

output of the explanation.

+5


source







All Articles