Aktualisierung:
Siehe diesen Artikel in meinem Blog für eine effiziente Indizierungsstrategie für Ihre Abfrage mit berechneten Spalten:
Die Hauptidee ist, dass wir einfach die gerundete length
berechnen und startDate
für Ihre Bereiche und suchen Sie sie dann unter Verwendung von Gleichheitsbedingungen (die gut für B-Tree
sind Indizes)
In MySQL
und in SQL Server 2008
Sie könnten SPATIAL
verwenden Indizes (R-Tree
).
Sie eignen sich besonders gut für Bedingungen wie "Alle Datensätze mit einem bestimmten Punkt innerhalb des Datensatzbereichs auswählen", was genau Ihr Fall ist.
Sie hinterlegen das start_date
und end_date
als Anfang und Ende eines LineString
(Konvertieren in UNIX
Zeitstempel eines anderen numerischen Werts), indizieren Sie sie mit einem SPATIAL
indexieren und nach allen solchen LineString
suchen s, deren minimaler Begrenzungsrahmen (MBR
) enthält den fraglichen Datumswert mithilfe von MBRContains
.
Siehe diesen Eintrag in meinem Blog, wie man das in MySQL
macht :
und eine kurze Leistungsübersicht für SQL Server
:
Die gleiche Lösung kann für die Suche nach einem bestimmten IP
angewendet werden gegen in der Datenbank gespeicherte Netzwerkbereiche.
Diese Aufgabe ist zusammen mit Ihrer Abfrage ein weiteres häufig verwendetes Beispiel für eine solche Bedingung.
Einfacher B-Tree
Indizes sind nicht gut, wenn sich die Bereiche überschneiden können.
Wenn dies nicht möglich ist (und Sie wissen es), können Sie die brillante Lösung verwenden, die von @AlexKuznetsov
vorgeschlagen wird
Beachten Sie auch, dass diese Abfrageleistung vollständig von Ihrer Datenverteilung abhängt.
Wenn Sie viele Datensätze in B
haben und wenige Aufzeichnungen in A
, könnten Sie einfach einen Index für B.dates
erstellen und lassen Sie den TS/CIS
auf A
gehen.
Diese Abfrage liest immer alle Zeilen von A
und verwendet Index Seek
am B.dates
in einer verschachtelten Schleife.
Werden Ihre Daten andersherum weitergegeben, d.h. e. Sie haben viele Zeilen in A
aber wenige in B
, und die Bereiche im Allgemeinen kurz sind, dann könnten Sie Ihre Tabellen ein wenig umgestalten:
A
start_date interval_length
, erstellen Sie einen zusammengesetzten Index für A (interval_length, start_date)
und verwenden Sie diese Abfrage:
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