Mysql
 sql >> Database >  >> RDS >> Mysql

Join su indici mysql spaziali

Credo che sia perché MySQL non supporta l'unione di indici spaziali. Non sono sicuro che sia ancora vero, ma l'ho letto da qualche parte in passato. Se hai un'istruzione OR, gli indici spaziali non vengono utilizzati

Nel tuo caso, dove stai facendo points.id =1, questa è una selezione diretta con un risultato restituito che viene utilizzato in mbrcontains. Che usa l'indice.

Quando aggiungi punti.in (1,2,3), restituisce 3 risultati e ciascuno deve essere mappato sulla tabella degli intervalli, quindi non funziona

risultato

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   

Puoi semplificare il tuo test senza la tabella dei punti in questo modo:SELECT * FROM intervalli in cui 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 ora questo; SELECT * FROM intervalli in cui mbrcontains( poly, GEOMFROMWKB(POINT(0, 0))) O mbrcontains( poly, GEOMFROMWKB(POINT(10, 10)))

risultato

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

Vedi che nel secondo caso, non stai usando l'indice e stai solo scansionando.

Potresti forzare la query a utilizzare l'indice creando UNION per ogni punto specifico, ma non sono sicuro che sarà più veloce. Ho eseguito alcuni test in locale ed è stato un po' più lento della tua prima 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

risultato

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