sql >> Base de Datos >  >> RDS >> Mysql

Uniones en índices mysql espaciales

Creo que es porque MySQL no admite la combinación de índices espaciales. No estoy seguro de si sigue siendo cierto, pero lo he leído en algún lugar en el pasado. Si tiene una declaración OR, entonces los índices espaciales no se usan

En su caso, ¿dónde está haciendo points.id =1? Esa es una selección directa con un resultado devuelto que se usa en mbrcontains. Eso usa el índice.

Cuando agrega puntos.in (1,2,3), eso devuelve 3 resultados y cada uno debe asignarse a la tabla de rangos, por lo tanto, no funciona

resultado

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   

Puede simplificar su prueba sin la tabla de puntos haciendo esto: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

Y ahora esto; SELECCIONE * DESDE rangos donde mbrcontains( poly, GEOMFROMWKB(POINT(0, 0))) O mbrcontains( poly, GEOMFROMWKB(POINT(10, 10)))

resultado

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

Vea que en el segundo caso, no está usando el índice y solo escaneando.

Puede obligar a la consulta a usar el índice creando UNION para cada punto específico, pero no estoy seguro de si eso será más rápido. Hice algunas pruebas localmente y fue un poco más lento que tu primera consulta.

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

resultado

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    <union1,2,3>    ALL     NULL    NULL    NULL    NULL    NULL    NULL