Aggiornamento:
Vedi questo articolo nel mio blog per una strategia di indicizzazione efficiente per la tua query utilizzando colonne calcolate:
L'idea principale è che calcoliamo semplicemente la length
arrotondata e startDate
per te intervalli e quindi cercali utilizzando condizioni di uguaglianza (che sono buone per B-Tree
indici)
In MySQL
e in SQL Server 2008
potresti usare SPATIAL
indici (R-Tree
).
Sono particolarmente utili per condizioni come "seleziona tutti i record con un determinato punto all'interno dell'intervallo del record", che è proprio il tuo caso.
Memorizzi il start_date
e end_date
come inizio e fine di una LineString
(convertendoli in UNIX
timestamp di un altro valore numerico), indicizzarli con un SPATIAL
indicizza e cerca tutti questi LineString
s il cui riquadro di delimitazione minimo (MBR
) contiene il valore della data in questione, utilizzando MBRContains
.
Vedi questa voce nel mio blog su come farlo in MySQL
:
e una breve panoramica delle prestazioni per SQL Server
:
La stessa soluzione può essere applicata per la ricerca di un dato IP
rispetto agli intervalli di rete archiviati nel database.
Questa attività, insieme alla tua query, è un altro esempio usato spesso di tale condizione.
B-Tree
semplice gli indici non vanno bene se gli intervalli possono sovrapporsi.
Se non possono (e tu lo sai), puoi utilizzare la brillante soluzione proposta da @AlexKuznetsov
Tieni inoltre presente che le prestazioni di questa query dipendono totalmente dalla distribuzione dei dati.
Se hai molti record in B
e pochi record in A
, potresti semplicemente creare un indice su B.dates
e lascia che il TS/CIS
su A
vai.
Questa query leggerà sempre tutte le righe da A
e utilizzerà Index Seek
su B.dates
in un ciclo annidato.
Se i tuoi dati sono distribuiti in modo diverso, i. e. hai molte righe in A
ma pochi in B
, e gli intervalli sono generalmente brevi, puoi riprogettare un po' le tue tabelle:
A
start_date interval_length
, crea un indice composito su A (interval_length, start_date)
e usa questa query:
SELECT *
FROM (
SELECT DISTINCT interval_length
FROM a
) ai
CROSS JOIN
b
JOIN a
ON a.interval_length = ai.interval_length
AND a.start_date BETWEEN b.date - ai.interval_length AND b.date