Verbesserung der Leistung von STIntersects

11

Tabelle T_PINhat 300.000 Stifte und T_POLYGONhat 36.000 Polygone. T_PINhat diesen Index:

CREATE SPATIAL INDEX [T_PIN_COORD] ON [dbo].[T_PIN]
(
[Coord]
)USING  GEOGRAPHY_GRID 
WITH (GRIDS =(LEVEL_1 = HIGH,LEVEL_2 = HIGH,LEVEL_3 = HIGH,LEVEL_4 = HIGH), 
CELLS_PER_OBJECT = 128, PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, 
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY];

T_POLYGON hat:

CREATE SPATIAL INDEX [T_POLYGON_COORD] ON [dbo].[T_POLYGON]
(
[COORD]
)USING  GEOGRAPHY_GRID 
WITH (GRIDS =(LEVEL_1 = HIGH,LEVEL_2 = HIGH,LEVEL_3 = HIGH,LEVEL_4 = HIGH), 
CELLS_PER_OBJECT = 128, PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, 
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) 
ON [PRIMARY];

Eine Abfrage zum Ermitteln des Schnittpunkts von T_PINund T_POLYGONdie Ausführung dauert mehr als 45 Minuten:

SELECT COUNT(*)
FROM T_PIN 
INNER JOIN T_POLYGON
    ON T_PIN.Coord.STIntersects(T_POLYGON.COORD) = 1;

Das Ergebnis sind 4.438.318 Zeilen.

Wie kann ich diese Abfrage beschleunigen?

seb49
quelle
Haben Sie versucht, "T_POLYGON.Coord.STIntersects (T_PIN.COORD) = 1" zu verwenden?
Travis
Es würde mich interessieren, Ihren Abfrageplan zu sehen. Ich arbeite an Postgres, muss aber ähnliche Abfragen ausführen, aber an wesentlich größeren Datenmengen. Ich habe eine Technik entwickelt, die meine schlimmsten auf ungefähr 2 Tage reduziert (was leider das Erstellen von Skripten beinhaltet), aber ich wäre interessiert, zuerst Ihren Abfrageplan zu sehen.
John Powell
Wenn ich die Polygone in meinen beiden Tabellen miteinander multipliziere, habe ich eine Zahl, die in Bezug auf die Anzahl der möglichen Schnittpunkte 7000-mal höher ist als in Ihrer Kombination. Daher denke ich, dass meine zwei Tage in diesem Licht ziemlich gut aussehen. Ohne einen Abfrageplan zu sehen und etwas über die durchschnittliche Anzahl von Punkten pro Polygon zu wissen, wird es jedoch schwierig sein, konkrete Lösungen zu finden.
John Powell

Antworten:

7

Überprüfen Sie zunächst anhand des Abfrageausführungsplans, ob ein räumlicher Index verwendet wird, und prüfen Sie, ob ein Element für die Suche nach Clustered Index (Spatial) vorhanden ist.

Angenommen, es wird verwendet, können Sie versuchen, einen sekundären / vereinfachten Filter basierend auf einem Begrenzungsrahmen mit vereinfachten Polygonen hinzuzufügen, um zuerst zu prüfen. Übereinstimmungen mit diesen vereinfachten Polygonen könnten dann durch den Primärfilter geführt werden, um die Endergebnisse zu erhalten.

1) Fügen Sie der Tabelle [dbo] eine neue Geografie- und Geometriespalte hinzu. [T_POLYGON] -Tabelle:

ALTER TABLE [dbo].[T_POLYGON] ADD SimplePolysGeom geometry;
ALTER TABLE [dbo].[T_POLYGON] ADD SimplePolysGeog geography;

2) Erstellen Sie die Begrenzungsrahmen-Polygone (dies beinhaltet eine anfängliche Konvertierung in Geometrie, um STEnvelope () zu nutzen):

UPDATE [dbo].[T_POLYGON] SET SimplePolysGeom = geometry::STGeomFromWKB(
    COORD.STAsBinary(), COORD.STSrid).STEnvelope();

UPDATE [dbo].[T_POLYGON] SET SimplePolysGeog = geography::STGeomFromWKB(
    SimplePolysGeom.STAsBinary(), SimplePolysGeom.STSrid);

3) Erstellen Sie einen räumlichen Index für die vereinfachte Geografiespalte

4) Holen Sie sich die Schnittpunkte für diese vereinfachte Geografiespalte und filtern Sie erneut nach den übereinstimmenden Geografiedatentypen. Etwa so etwas:

;WITH cte AS
(
   SELECT pinID, polygonID FROM T_PIN INNER JOIN T_POLYGON
    ON T_PIN.Coord.STIntersects(T_POLYGON.SimplePolysGeog ) = 1
)
SELECT COUNT(*)
FROM T_PIN 
INNER JOIN T_POLYGON
    ON T_PIN.Coord.STIntersects(T_POLYGON.COORD) = 1
    AND T_PIN.pinID IN (SELECT pinID FROM cte)
    AND T_POLYGON.polygonID IN (SELECT polygonID FROM cte)

BEARBEITEN : Sie können (1) und (2) durch diese berechnete, persistente Spalte ersetzen. Dank an Paul White für den Vorschlag.

ALTER TABLE [dbo].[T_POLYGON] ADD SimplePolysGeog AS  ([geography]::STGeomFromWKB([geometry]::STGeomFromWKB([COORD].[STAsBinary](),[COORD].[STSrid]).STEnvelope().STAsBinary(),(4326))) PERSISTED
g2server
quelle
Ja, das war mehr oder weniger das, worauf ich hinaus wollte. Das Problem, das ich beim räumlichen "Zusammenfügen" von zwei Tabellensätzen mit einem großen Abdeckungsbereich festgestellt habe, ist, dass der Optimierer in Polygontests häufig zwei vollständige Tabellenscans und Punktladungen ausführt.
John Powell
2

Abfragen wie diese dauern aufgrund der Komplexität der Polygone oft lange. Ich habe gesehen, dass komplexe Küsten (zum Beispiel) ewig brauchen, um Punkte zu testen, die nahe an ihren Grenzen liegen, und viele Ebenen zoomen müssen, um festzustellen, ob sich ein Punkt innerhalb oder außerhalb befindet.

... also könntest du es versuchen .Reduce() , die Polygone zu verwenden, um zu sehen, ob das hilft.

Weitere Informationen zu dieser Funktion finden Sie unter http://msdn.microsoft.com/en-us/library/cc627410.aspx

Rob Farley
quelle
1

Laut Microsoft-Dokumenten werden räumliche Indizes mit Geografietypen für die folgenden Methoden verwendet, wenn sie am Anfang eines Vergleichsprädikats mit einer WHEREKlausel angezeigt werden:

  • STIntersects
  • STDistance
  • STEquals

Nur die Methoden der Geometrietypen (eingeschränkte Liste) lösen die Verwendung des räumlichen Index in aus JOIN ... ON. Ändern Sie daher den zu verwendenden CodeWHERE geog1.STIntersects(geog2) = 1 die Geschwindigkeit zu verbessern.

Ich empfehle außerdem, sich in der Antwort von g2server beraten zu lassen und Folgendes zum Filtern hinzuzufügen und einen räumlichen Index hinzuzufügen

ALTER TABLE [dbo].[T_POLYGON] ADD SimplePolysGeog AS
     ([geography]::STGeomFromWKB([geometry]::STGeomFromWKB([COORD].[STAsBinary](),
                                                           [COORD].[STSrid])
                 .STEnvelope().STAsBinary(),(4326))) PERSISTED

Sie könnten dann eine Abfrage wie die folgende haben (ich habe diesen Beitrag schnell geschrieben und noch nicht getestet. Dies ist nur ein Versuch, da ich gesehen habe, dass Ihre Abfrage und die am höchsten geposteten Antworten JOIN ON räumlich op = 1 verwenden, wobei a nicht verwendet wird räumlicher Index):

SELECT   
     (SELECT p2.polygon_id
      FROM   T_Polygon p2
      WHERE  p2.coords.STIntersects(t.coords) = 1),
     t.pin_id
FROM     T_PIN t
WHERE    
     (SELECT t.coords.STIntersects(p.coords)
      FROM   T_POLYGON p
      WHERE  t.coords.STIntersects(p.SimplePolysGeog) = 1) = 1

Zu Ihrer Information: Das oben genannte funktioniert nicht, wenn SimplePolysGeog Ihrer Information Genannte Ende überlappt (wie in einem Pin in zwei vereinfachten Geogs, kann dies nur für Personen in Bezirken in einem Bundesstaat ausgeführt werden und da sich normale Polys die Grenzen teilen, überlappen sich die Begrenzungsrahmen), so dass sie in den meisten Fällen verwendet werden In diesen Fällen wird der Fehler ausgegeben, dass die Unterabfrage mehr als ein Ergebnis zurückgegeben hat.

Aus der Übersicht über die räumlichen Indizes von MS Docs :

Geografische Methoden, die von räumlichen Indizes unterstützt werden

Unter bestimmten Bedingungen unterstützen räumliche Indizes die folgenden satzorientierten Geografiemethoden: STIntersects (), STEquals () und STDistance (). Um von einem räumlichen Index unterstützt zu werden, müssen diese Methoden in der WHERE-Klausel einer Abfrage verwendet werden und in einem Prädikat der folgenden allgemeinen Form vorkommen:

geography1.method_name (geography2) compare_operatorvalid_number

Um ein Ergebnis ungleich Null zurückzugeben, müssen Geografie1 und Geografie2 dieselbe räumliche Referenzkennung (Spatial Reference Identifier, SRID) haben . Andernfalls gibt die Methode NULL zurück.

Raumindizes unterstützen die folgenden Prädikatformen:


Abfragen, die räumliche Indizes verwenden

Raumindizes werden nur in Abfragen unterstützt, die einen indizierten Raumoperator in der WHERE-Klausel enthalten. Zum Beispiel Syntax wie:

[spatial object].SpatialMethod([reference spatial object]) [ = | < ] [const literal or variable]

Der Abfrageoptimierer versteht die Kommutativität räumlicher Operationen (das @a.STIntersects(@b) = @b.STInterestcs(@a)). Der räumliche Index wird jedoch nicht verwendet, wenn der Beginn eines Vergleichs den räumlichen Operator nicht enthält (z. B. WHERE 1 = spatial opwird der räumliche Index nicht verwendet). Um den räumlichen Index zu verwenden, schreiben Sie den Vergleich neu (zum Beispiel WHERE spatial op = 1).

...

Die folgende Abfrage funktioniert bei SimplePolysGeogsÜberlappung:

;WITH cte AS
(
   SELECT T_PIN.PIN_ID, 
          T_POLYGON.POLYGON_ID, 
          T_POLYGON.COORD 
   FROM T_PIN 
   INNER JOIN T_POLYGON
   ON T_PIN.COORD.STIntersects(T_POLYGON.SimplePolysGeog) = 1
)

SELECT COUNT(*)
FROM T_PIN 
INNER JOIN cte
ON T_PIN_PIN_ID = cte.PIN_ID
where cte.[COORD].STIntersects(T_PIN.COORD) = 1
pbordeaux
quelle