Come ottimizzare una query in modo che cerchi prima un indice, quindi un altro indice


12

Ho due serie di misurazioni della terra da dati satellitari, ognuna con campi temporali (mjd per data media giuliana) e posizioni geografiche (GeoPoint, spaziale) e sto cercando coincidenze tra le due serie in modo che i loro tempi corrispondano a una soglia di 3 ore (o .125 giorni) e le loro distanze entro 200 km l'una dall'altra.

Ho creato degli indici per entrambi i campi mjd su entrambe le tabelle e le tabelle spaziali.

Quando mi unisco al vincolo temporale, il database calcola 100.000 partite in 8 secondi e calcola le distanze per tutte le 100.000 partite in quel momento. La query è simile alla seguente:

select top 100000 h.Time, m.Time, h.GeoPoint.STDistance(m.GeoPoint)/1000.0
from L2V5.dbo.header h join L2.dbo.MLS_Header m
on h.mjd between m.mjd-.125 and m.mjd+.125
option( table hint ( h, index(ix_MJD) ), table hint( m, index(ix_MJD) ) )

E il piano eseguito è:

Solo vincolo mjd

Una volta ordinati, 9 delle distanze erano inferiori a 200 km, quindi ci sono partite. Il problema è che quando aggiungo il vincolo di distanza ed eseguo invece questo,

select top 10 h.Time, m.Time, h.GeoPoint.STDistance(m.GeoPoint)/1000.0
from L2V5.dbo.header h join L2.dbo.MLS_Header m
on h.mjd between m.mjd-.125 and m.mjd+.125
and h.GeoPoint.STDistance(m.GeoPoint)<200000
option( table hint ( h, index(ix_MJD) ), table hint( m, index(ix_MJD) ) )

va via per molto tempo. Ovviamente, in 8 secondi, è stato possibile trovare 100.000 fiammiferi, di cui 9 a meno di 200 km, quindi l'ottimizzatore deve provare qualcosa di non ottimale. Il piano è simile al precedente con un filtro sulle distanze (immagino).

con costrutti spaziali, nessun filtro spaziale

Posso forzare l'uso dell'indice spaziale con questo:

select top 5 h.Time, m.Time, h.GeoPoint.STDistance(m.GeoPoint)/1000.0 
from L2V5.dbo.header h join L2.dbo.MLS_Header m 
on h.GeoPoint.STDistance(m.GeoPoint)<200000
and h.mjd between m.mjd-.125 and m.mjd+.125 
option( table hint ( h, index(ix_MJD), index(ix_GeoPoint) ), table hint( m, index(ix_MJD) ) )

entrambi i vincoli con entrambi gli indici

che quindi impiega 3 minuti per trovare 5 partite.

Come faccio a dire a Query Optimizer di usare prima l'indice MJD, e poi l'indice spaziale secondo (o è quello che sta già facendo) e c'è un modo per aiutarlo dicendogli quante partite aspettarsi? Se è in grado di calcolare 100.000 partite con distanze in 8 secondi che hanno 9 sotto 200 km, l'aggiunta dell'indice spaziale non dovrebbe renderlo più veloce, non più lento?

Grazie per eventuali altri suggerimenti o idee.

EDIT: per rispondere alla domanda che aspetto ha il piano senza i suggerimenti, questo (e ci vorrà per sempre):

nessun suggerimento

Vale anche la pena ricordare che ci sono quasi 1 milione di record in una tabella e 8 milioni nell'altra


Che aspetto ha il tuo piano di query se rimuovi questi suggerimenti?
Zane,

@Zane, ho modificato il post e aggiunto il piano di query senza suggerimenti. Sostituisce le ricerche con scansioni e il tempismo è spaventoso.
user261963

Risposte:


6

Il problema è che potrebbe (e conoscendo gli indici spaziali, probabilmente) supporre che il filtro spaziale sarà molto più selettivo del filtro temporale.

Ma se hai qualche milione di dischi entro 200 km, potrebbe essere significativamente peggio.

Lo stai chiedendo di trovare i record entro 200 km, che restituisce i dati ordinati per ordine spaziale. Trovare i record lì dentro che sono vicini nel tempo significa controllarli.

Altrimenti stai trovando i record per tempo e stai ottenendo risultati in ordine di tempo. Quindi, filtrare questo elenco nel raggio di 200 km è una questione di controllo di ciascuno.

Se si filtrano i dati in due intervalli come questo, diventa difficile applicare il secondo filtro utilizzando un indice. Potrebbe essere meglio dirgli di non usare l'indice spaziale se il filtro temporale è quello più stretto.

Se entrambi sono grandi individualmente, ed è solo insieme che sono stretti, allora hai un problema più complesso, uno che le persone hanno cercato di risolvere da molto tempo e che potrebbe essere ben risolto da indici che coprono il 3D (e oltre) spazio. Tranne che SQL Server non li ha.

Scusa.

Modifica: maggiori informazioni ...

Questo è un problema simile alla ricerca di intervalli di tempo che coprono un determinato momento. Quando cerchi i record che iniziano prima di quel momento, hai un disordine non ordinato di tempi di fine e viceversa. Se cerchi persone nella rubrica i cui cognomi iniziano con F, non puoi sperare di trovare facilmente le persone i cui nomi iniziano con R. E un indice sul nome non aiuta neanche per lo stesso motivo. Trovare le cose nel prossimo indice è difficile quando il tuo primo indice non è un'uguaglianza.

Ora, se potessi cambiare il tuo filtro data in un filtro di uguaglianza (o una serie di filtri di uguaglianza), allora potresti avere una possibilità, tranne che un indice spaziale è un tipo speciale di indice e non può essere usato come secondo livello in un indice composito.

Quindi ti rimane una situazione imbarazzante, temo. :(

Modifica: prova:

select top 100000 h.Time, m.Time, h.GeoPoint.STDistance(m.GeoPoint)/1000.0
from L2V5.dbo.header h join L2.dbo.MLS_Header m
on h.mjd between m.mjd-.125 and m.mjd+.125
where h.GeoPoint.STDistance(m.GeoPoint)/1000.0 < 200
option( table hint ( h, index(ix_MJD) ) );

Si noti che sto deliberatamente rompendo la sargibilità dividendo per 1000 prima di confrontarlo con 200. Voglio che questo lavoro sia svolto nella Ricerca chiave.

Intendiamoci, potresti evitare la necessità delle ricerche (e dei suggerimenti) INCLUDENDO GeoPoint e Time in entrambi gli indici ix_MJD. Questo certamente toglierà un po 'di calore dal piano di query.


Non so se cambia qualcosa, ma il filtro temporale è molto più selettivo.
user261963,

Ok. Quindi è accettabile individuare tutte le righe con corrispondenza temporale e quindi controllare ogni posizione senza l'indice?
Rob Farley,

... quindi il piano sembra quello originale, ma ha un predicato o un filtro extra.
Rob Farley,

Ha suggerito alcune modifiche con una modifica rapida. Non hai bisogno di accennare a m, solo h. Anche se puoi scambiare quello a cui stai aggiungendo 1/8, per assicurarti di modificare la colonna dalla tabella più piccola e usare quei valori per cercare quello più grande, anche questo ti aiuterà. Se h è 8M e m è 1M, lasciare il predicato TRA e suggerire solo h. Se è il contrario, cambia il tuo predicato e il tuo suggerimento (ma meglio che cambiare il suggerimento è aggiungere quelle colonne al tuo indice).
Rob Farley,

Eliminare tutti i suggerimenti per la tabella sembra funzionare meglio alla fine, fintanto che faccio h tra me e non viceversa. La query non utilizza più affatto gli indici GeoPoint, ma comunque non li utilizzava in modo efficiente. Ho incluso la colonna GeoPoint nell'indice MJD e questo mi ha aiutato molto. select top 10000 h.Time, m.Time, m.GeoPoint.STDistance(h.GeoPoint), h.mjd-m.mjd from L2V5.dbo.header h join L2.dbo.MLS_Header m on m.GeoPoint.STDistance(h.GeoPoint)<200000 and m.mjd between h.mjd-.125 and h.mjd+.125 order by h.mjd
user261963
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.