So optimieren Sie eine Abfrage so, dass sie zuerst einen Index und danach einen anderen Index durchsucht

12

Ich habe zwei Sätze von Erdmessungen aus Satellitendaten, jeweils mit Zeitfeldern (mjd für Mean Julian Date) und geografischen Positionen (GeoPoint, Spacial), und ich suche nach Übereinstimmungen zwischen den beiden Sätzen, so dass ihre Zeiten mit einem Schwellenwert von übereinstimmen 3 Stunden (oder .125 Tage) und deren Entfernungen bis zu 200 km voneinander entfernt.

Ich habe sowohl für Tabellen als auch für räumliche Tabellen Indizes für die mjd-Felder erstellt.

Wenn ich mich nur der Zeitbeschränkung anschließe, berechnet die Datenbank 100.000 Übereinstimmungen in 8 Sekunden und berechnet die Entfernungen für alle 100.000 Übereinstimmungen in dieser Zeit. Die Abfrage sieht folgendermaßen aus:

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) ) )

Und der ausgeführte Plan ist:

Nur mjd Einschränkung

Bei Sortierung lagen 9 der Entfernungen unter 200 km, es gibt also Übereinstimmungen. Das Problem ist, wenn ich die Abstandsbeschränkung hinzufüge und diese stattdessen ausführe,

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) ) )

es geht für eine lange Zeit weg. Offensichtlich konnte es in 8 Sekunden 100.000 Zeitmatches finden, von denen 9 unter 200 km lagen. Der Optimierer muss also etwas suboptimales ausprobieren. Der Plan sieht ähnlich aus wie oben mit einem Filter für die Entfernungen (ich vermute).

mit räumlicher Konstante, kein räumlicher Filter

Damit kann ich die Verwendung des räumlichen Index erzwingen:

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) ) )

beide Einschränkungen mit beiden Indizes

Das dauert dann 3 Minuten, um 5 Übereinstimmungen zu finden.

Wie kann ich das Abfrageoptimierungsprogramm anweisen, zuerst die MJD-Indexsuche und dann die räumliche Indexsuche zu verwenden (oder ist es das, was es bereits tut)? Wenn es 100.000 Übereinstimmungen mit Entfernungen in 8 Sekunden mit 9 unter 200 km berechnen kann, sollte die Addition des räumlichen Index es nicht schneller und nicht langsamer machen?

Vielen Dank für weitere Tipps oder Ideen.

EDIT: Um die Frage zu beantworten, wie der Plan ohne die Hinweise aussieht, ist dies (und es dauert ewig):

keine Hinweise

Es ist vielleicht auch erwähnenswert, dass die eine Tabelle fast 1 Million Datensätze und die andere 8 Millionen Datensätze enthält

user261963
quelle
Wie sieht Ihr Abfrageplan aus, wenn Sie diese Hinweise entfernen?
Zane
@Zane, ich habe den Beitrag bearbeitet und den No-Hint-Abfrageplan hinzugefügt. Es ersetzt die Suchanfragen durch Scans und das Timing ist miserabel.
user261963

Antworten:

6

Das Problem ist, dass es davon ausgehen könnte (und wenn man räumliche Indizes kennt, wird dies wahrscheinlich der Fall sein), dass der räumliche Filter viel selektiver ist als der Zeitfilter.

Aber wenn Sie ein paar Millionen Datensätze innerhalb von 200 km haben, könnte es bedeutend schlimmer sein.

Sie fordern ihn auf, Datensätze innerhalb von 200 km zu finden, die Daten in räumlicher Reihenfolge zurückgeben. Wenn Sie die zeitnahen Datensätze dort finden, müssen Sie jeden einzelnen überprüfen.

Oder Sie finden Datensätze nach Zeit und erhalten Ergebnisse in zeitlicher Reihenfolge. Das Filtern dieser Liste auf den Radius von 200 km ist eine Frage der Überprüfung.

Wenn Sie die Daten in zwei Bereichen filtern, wird es schwierig, den zweiten Filter mithilfe eines Index anzuwenden. Es empfiehlt sich möglicherweise, den räumlichen Index nicht zu verwenden, wenn der Zeitfilter enger ist.

Wenn beide einzeln groß sind und sie nur zusammen eng sind, haben Sie ein komplexeres Problem, das die Leute seit langem zu lösen versucht haben und das durch Indizes, die 3D (und darüber hinaus) abdecken, gut gelöst werden kann. Raum. Nur dass SQL Server sie nicht hat.

Es tut uns leid.

Bearbeiten: mehr Infos ...

Dies ist ein ähnliches Problem wie das Auffinden von Zeitbereichen, die einen bestimmten Zeitpunkt abdecken. Wenn Sie nach Datensätzen suchen, die vor diesem Zeitpunkt beginnen, gibt es ein ungeordnetes Durcheinander der Endzeiten - und umgekehrt. Wenn Sie im Telefonbuch nach Personen suchen, deren Nachnamen mit F beginnen, können Sie nicht hoffen, die Personen zu finden, deren Vornamen sehr leicht mit R beginnen. Und auch ein Index zum Vornamen hilft aus dem gleichen Grund nicht. Das Finden von Dingen in diesem nächsten Index ist schwierig, wenn Ihr erster Index keine Gleichheit ist.

Wenn Sie nun Ihren Datumsfilter in einen Gleichheitsfilter (oder eine Reihe von Gleichheitsfiltern) ändern könnten, hätten Sie eine Chance, mit der Ausnahme, dass ein räumlicher Index eine spezielle Art von Index ist und nicht als zweite Ebene in verwendet werden kann ein zusammengesetzter Index.

Ich fürchte, Sie haben eine unangenehme Situation. :(

Bearbeiten: Versuchen:

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) ) );

Beachten Sie, dass ich vor dem Vergleich mit 200 absichtlich die Sargabilität durch Division durch 1000 unterbreche. Ich möchte, dass diese Arbeit in der Schlüsselsuche ausgeführt wird.

Wohlgemerkt, Sie könnten die Notwendigkeit von Nachschlägen (und Hinweisen) vermeiden, indem Sie GeoPoint und Time in beiden ix_MJD-Indizes einschließen. Das wird dem Abfrageplan sicherlich etwas Wärme entziehen.

Rob Farley
quelle
Ich weiß nicht, ob es irgendetwas ändert, aber der Zeitfilter ist viel selektiver.
user261963
In Ordnung. Ist es also akzeptabel, alle zeitlich übereinstimmenden Zeilen zu lokalisieren und dann jede Position ohne den Index zu überprüfen?
Rob Farley
... dann sieht der Plan so aus wie der ursprüngliche, hat aber ein zusätzliches Prädikat oder einen zusätzlichen Filter.
Rob Farley
Schlug einige Änderungen mit einer schnellen Bearbeitung vor. Sie müssen nicht auf m hinweisen, nur auf h. Wenn Sie jedoch die Spalte, zu der Sie 1/8 hinzufügen, austauschen können, um sicherzustellen, dass Sie die Spalte aus der kleineren Tabelle ändern und diese Werte für die Suche in der größeren Tabelle verwenden, ist dies ebenfalls hilfreich. Wenn h 8M und m 1M ist, lassen Sie das ZWISCHEN-Prädikat und geben Sie nur h an. Wenn es umgekehrt ist, ändern Sie Ihr Prädikat und Ihren Hinweis (besser als den Hinweis, fügen Sie diese Spalten zu Ihrem Index hinzu).
Rob Farley
Das Herausnehmen aller Tabellenhinweise scheint am Ende am besten zu funktionieren, solange ich zwischen m und nicht umgekehrt arbeite. In der Abfrage werden die GeoPoint-Indizes nicht mehr verwendet, sie wurden jedoch ohnehin nicht effizient verwendet. Ich habe die GeoPoint-Spalte in den MJD-Index aufgenommen, und das hat mir sehr geholfen. 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