Scarse prestazioni quando si utilizzano gli indici spaziali in MySQL


13

Ripubblicazione di una domanda posta su Stack Overflow quando è stato suggerito che questo sarebbe un forum migliore.

Sto provando un piccolo esperimento a spingere un set di dati che non è geospaziale ma si adatta abbastanza bene e sto trovando i risultati un po 'inquietanti. Il set di dati è costituito da dati genomici, ad esempio il genoma umano, in cui abbiamo una regione di DNA in cui elementi come i geni occupano specifiche coordinate di inizio e fine (il nostro asse X). Abbiamo più regioni di DNA (cromosomi) che occupano l'asse Y. L'obiettivo è riportare tutti gli elementi che intersecano due coordinate X lungo una singola coordinata Y, ad esempio LineString (START 1, END 2).

La teoria sembrava solida, quindi l'ho spinto in un progetto di genoma basato su MySQL esistente e ho inventato una struttura di tabella come:

CREATE TABLE `spatial_feature` (
  `spatial_feature_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `external_id` int(10) unsigned NOT NULL,
  `external_type` int(3) unsigned NOT NULL,
  `location` geometry NOT NULL,
  PRIMARY KEY (`spatial_feature_id`),
  SPATIAL KEY `sf_location_idx` (`location`)
) ENGINE=MyISAM;

external_idrappresenta l'identificatore dell'entità che abbiamo codificato in questa tabella e external_typecodifica la fonte di ciò. Tutto sembrava a posto e ho inserito alcuni dati preliminari (30.000 righe) che sembravano funzionare bene. Quando questo ha superato i 3 milioni di righe, MySQL ha rifiutato di utilizzare l'indice spaziale ed è stato più lento quando è stato costretto a usarlo (40 secondi contro 5 secondi usando una scansione completa della tabella). Quando sono stati aggiunti più dati, l'indice ha iniziato a essere utilizzato, ma la penalità per le prestazioni persisteva. La disattivazione dell'indice ha portato la query a 8 secondi. La query che sto usando è simile a:

select count(*)
from spatial_feature
where MBRIntersects(GeomFromText('LineString(7420023 1, 7420023 1)'), location);

I dati che vanno in questo sono molto densi lungo le dimensioni Y (pensateci come se aveste registrato la posizione di ogni edificio, cabina telefonica, casella postale e piccione su una strada molto lunga). Ho fatto dei test su come si comportano gli R-Indexes con questi dati in Java e altri nel campo li hanno applicati con successo ai formati di file flat. Tuttavia nessuno li ha applicati ai database AFAIK che è l'obiettivo di questo test.

Qualcuno ha visto un comportamento simile quando si aggiungono grandi quantità di dati a un modello spaziale che non è molto disparato lungo un determinato asse? Il problema persiste se invertisco l'utilizzo delle coordinate. Sto eseguendo la seguente configurazione se questa è una causa

  • MacOS 10.6.6
  • MySQL 5.1.46

Risposte:


5

MySQL, come PostGIS, memorizza i dati dell'indice spaziale in una struttura ad albero R in modo da poter trovare rapidamente le cose. Un albero a R, come un albero a B, è organizzato in modo tale da essere ottimizzato per recuperare solo una piccola parte dei dati totali nella tabella. In realtà è più veloce ignorare l'indice per le query che devono leggere un'ampia sezione della tabella per restituire dati o eseguire un join enorme, un caso classico che dà origine a molti forum di database [poster] che si lamentano di una query che restituisce metà del loro tabella "non utilizzando il nuovo indice appena creato."

Da http://rickonrails.wordpress.com/2009/03/30/big-ole-mysql-spatial-table-optimization-tricks/

Se riesci ad adattare tutti i dati della tabella nella memoria, le tue prestazioni sono buone. Se / quando è necessario iniziare a fare letture del disco, le prestazioni peggiorano rapidamente. Stavi facendo schemi di utilizzo della memoria della tua istanza mysql per i due casi: 30k righe contro 3000k righe?


Penso che questo potrebbe essere più vicino al problema. TBH è l'indice R che voglio; l'altra matematica spaziale è un bel bonus poiché dovrebbe essere fatto nel livello API sotto il vecchio sistema. Ho provato un po 'di ottimizzazione, ma l'aumento dei buffer dei tasti non ha aiutato (altri buffer non aiuteranno qui come il buffer di tabella poiché è una query di 1 tabella sul mio server personale). Ciò che è strano è che MySQL martella la mia macchina nel terreno quando vengono eseguite le query (100% durante l'esecuzione della query). Detto questo, sta eseguendo una scansione completa del tavolo, quindi forse non è strano
andeyatz,

5

Qualcosa deve essere sbagliato nell'installazione di mysql o nelle impostazioni .ini. Ho appena testato un indice geospaziale sul mio vecchio mac (10.6.8 / MySQL 5.2). Quella configurazione è simile alla tua e ho testato il grande dump di geodati ( 9 milioni di record ). Ho fatto questa domanda:

SET @radius = 30;
SET @center = GeomFromText('POINT(51.51359 7.465425)');
SET @r = @radius/69.1;
SET @bbox = CONCAT('POLYGON((', 
  X(@center) - @r, ' ', Y(@center) - @r, ',', 
  X(@center) + @r, ' ', Y(@center) - @r, ',', 
  X(@center) + @r, ' ', Y(@center) + @r, ',', 
  X(@center) - @r, ' ', Y(@center) + @r, ',', 
  X(@center) - @r, ' ', Y(@center) - @r, '))' 
);

SELECT geonameid, SQRT(POW( ABS( X(point) - X(@center)), 2) + POW( ABS(Y(point) - Y(@center)), 2 ))*69.1 
AS distance
FROM TABLENAME AS root
WHERE Intersects( point, GeomFromText(@bbox) ) 
AND SQRT(POW( ABS( X(point) - X(@center)), 2) + POW( ABS(Y(point) - Y(@center)), 2 )) < @r 
ORDER BY distance; 

Ci sono voluti solo 0,0336 sec.

Uso la query di cui sopra, ad esempio per confronti tra tabelle in cui la tabella da cui provengono solo i valori lat / lng per @center ha un semplice INDICE da city_latitude / city_longitude e 9-12 Mio. tabella da geonames.org ha un indice geospaziale.

E volevo solo aggiungere che quando qualcuno inserisce i big data in una tabella potrebbe essere più performante aggiungere l'indice dopo INSERT. Altrimenti ci vorrà più tempo per ogni riga che aggiungi ... [ma non è importante]


Wow, è davvero bello. Ora non sono sicuro di cosa stavo facendo male nei miei test. Una cosa che potrebbe causare un problema è la natura dei miei set di dati rispetto ai set di dati geospaziali più tradizionali. Detto questo, sto solo indovinando e non ho basi per questo. È geniale vedere che non è necessario forzare l'indice in memoria per ottenere la velocità.
andeyatz,

La clausola WHERE con il raggio potrebbe filtrare una buona parte della tabella dall'uso di un indice.
tmarthal,

2

Hai mai pensato di suddividerlo in due colonne 1D anziché in una singola colonna 2D?

L'ottimizzatore potrebbe essere soffocato su tutti i dati simili e avere due colonne con una maggiore varietà potrebbe aiutare.

Quello che potresti anche controllare è l'ordine in cui gli articoli sono controllati. Ho avuto un problema in Oracle Spatial in cui stavo cercando il cognome e un filtro IN_REGION. Oracle decise che il modo più veloce era usare il cognome e quindi fare un controllo della regione. Lascia che te lo dica, fare un controllo nella regione su tutti i Robinson di Cleveland è lento . Ricordo che dovevo passare un argomento specifico Oracle per costringerlo a utilizzare prima l'indice spaziale.


Sfortunatamente 1 dimensione è notevolmente meno popolata di un'altra dimensione. Per mettere questo nel contesto il genoma umano ha 24 cromosomi unici (22 coppie e i due cromosomi sessuali) insieme a un sacco di dati che è stato assemblato a diversi livelli. Ciò significa che se si mappano elementi al caso d'uso di base che contiene solo 24 identificatori univoci in una dimensione. La speranza originale era che l'indice R-tree sarebbe stato in grado di eseguire non solo controlli di intervallo sovrapposti più performanti, ma anche di differenziare queste regioni in una singola query.
Andeyatz,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.