Joins on spatial mysql indexes

后端 未结 4 2095
攒了一身酷
攒了一身酷 2021-02-08 03:59

I have two tables: one with points, the other with polys.

CREATE TABLE `points` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `point` point NOT NULL,
  PR         


        
4条回答
  •  耶瑟儿~
    2021-02-08 04:55

    I believe that it's because MySQL doesn't support merging spatial indexes. Not sure if it's still true but I've read it somewhere in the past. If you have an OR statement, then the spatial indexes are not used

    In your case, where are you doing points.id = 1, that's a straight select with one result returned that gets used in the mbrcontains. That uses the index.

    When you add points.in (1,2,3), that returns 3 results and each needs to be mapped to the ranges table, therefore not working

    result

    id  select_type     table   type    possible_keys   key     key_len     ref     rows    filtered    Extra
    1   SIMPLE  points  range   PRIMARY     PRIMARY     4   NULL    3   100.00  Using where
    1   SIMPLE  ranges  ALL     poly    NULL    NULL    NULL    6467418     100.00   
    

    You can simplify your test without the the point table by doing this: SELECT * FROM ranges where mbrcontains( poly, GEOMFROMWKB(POINT(0, 0)))

    id  select_type     table   type    possible_keys   key     key_len     ref     rows    filtered    Extra
    1   SIMPLE  ranges  range   poly    poly    34  NULL    1   100.00  Using where
    

    And now this; SELECT * FROM ranges where mbrcontains( poly, GEOMFROMWKB(POINT(0, 0))) OR mbrcontains( poly, GEOMFROMWKB(POINT(10, 10)))

    result

    id  select_type     table   type    possible_keys   key     key_len     ref     rows    filtered    Extra
    1   SIMPLE  ranges  ALL     poly    NULL    NULL    NULL    6467418     100.00  Using where
    

    See that in the second case, you are not using index and just scanning.

    You could force the query to use index by creating UNION for each specific point but I am not sure if that's going to be faster. I did some tests locally and it was a bit slower than your first query.

    EXPLAIN EXTENDED 
    SELECT *
    FROM points
    FORCE INDEX (PRIMARY )
    LEFT JOIN ranges
    FORCE INDEX ( poly ) ON mbrcontains( poly, point )
    WHERE points.id = 1
    UNION DISTINCT
    SELECT *
    FROM points
    FORCE INDEX (PRIMARY )
    LEFT JOIN ranges
    FORCE INDEX ( poly ) ON mbrcontains( poly, point )
    WHERE points.id = 2
    UNION DISTINCT
    SELECT *
    FROM points
    FORCE INDEX (PRIMARY )
    LEFT JOIN ranges
    FORCE INDEX ( poly ) ON mbrcontains( poly, point )
    WHERE points.id = 3
    

    result

    id  select_type     table   type    possible_keys   key     key_len     ref     rows    filtered    Extra
    1   PRIMARY     points  const   PRIMARY     PRIMARY     4   const   1   100.00   
    1   PRIMARY     ranges  range   poly    poly    34  NULL    1   100.00  Using where
    2   UNION   points  const   PRIMARY     PRIMARY     4   const   1   100.00   
    2   UNION   ranges  range   poly    poly    34  NULL    1   100.00  Using where
    3   UNION   points  const   PRIMARY     PRIMARY     4   const   1   100.00   
    3   UNION   ranges  range   poly    poly    34  NULL    1   100.00  Using where
    NULL    UNION RESULT        ALL     NULL    NULL    NULL    NULL    NULL    NULL     
    

提交回复
热议问题