Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Junções em índices espaciais do mysql


Acredito que seja porque o MySQL não suporta a mesclagem de índices espaciais. Não tenho certeza se ainda é verdade, mas eu li em algum lugar no passado. Se você tiver uma instrução OR, os índices espaciais não serão usados

No seu caso, onde você está fazendo points.id =1, isso é uma seleção direta com um resultado retornado que é usado no mbrcontains. Que usa o índice.

Quando você adiciona points.in (1,2,3), isso retorna 3 resultados e cada um precisa ser mapeado para a tabela de intervalos, portanto, não 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   

Você pode simplificar seu teste sem a tabela de pontos fazendo isso: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

E agora isso; SELECT * FROM intervalos em que mbrcontém(poli, GEOMFROMWKB(POINT(0, 0))) OU mbrcontém(poli, 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

Veja que no segundo caso, você não está usando index e apenas digitalizando.

Você pode forçar a consulta a usar o índice criando UNION para cada ponto específico, mas não tenho certeza se isso será mais rápido. Fiz alguns testes localmente e foi um pouco mais lento que sua primeira 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