Warum ist st_intersects schneller als &&


10

Es ist eine Punktetabelle. ~ 1 Million Datensätze

SELECT COUNT(*) as value FROM alasarr_social_mv s; 
Output: 976270

Es sieht so aus, als ob st_intersects die räumlichen Indizes verwenden muss, && jedoch nicht.

Probe mit ST_Intersects(282ms)

SELECT COUNT(*) as value
FROM alasarr_social_mv 
WHERE ST_Intersects(
  the_geom_webmercator, 
  ST_MakeEnvelope(-410961,4920492,-402305,4926887,3857)
)


Aggregate  (cost=34370.18..34370.19 rows=1 width=0) (actual time=282.715..282.715 rows=1 loops=1)
  ->  Bitmap Heap Scan on alasarr_social_mv s  (cost=5572.17..34339.84 rows=60683 width=0) (actual time=21.574..240.195 rows=178010 loops=1)
        Recheck Cond: (the_geom_webmercator && '0103000020110F0000010000000500000000000000441519C1000000002BC5524100000000441519C1000000C069CB524100000000048E18C1000000C069CB524100000000048E18C1000000002BC5524100000000441519C1000000002BC55241'::geometry)
        Filter: _st_intersects(the_geom_webmercator, '0103000020110F0000010000000500000000000000441519C1000000002BC5524100000000441519C1000000C069CB524100000000048E18C1000000C069CB524100000000048E18C1000000002BC5524100000000441519C1000000002BC55241'::geometry)
        Heap Blocks: exact=4848
        ->  Bitmap Index Scan on alasarr_social_mv_gix  (cost=0.00..5569.13 rows=182050 width=0) (actual time=20.836..20.836 rows=178010 loops=1)
              Index Cond: (the_geom_webmercator && '0103000020110F0000010000000500000000000000441519C1000000002BC5524100000000441519C1000000C069CB524100000000048E18C1000000C069CB524100000000048E18C1000000002BC5524100000000441519C1000000002BC55241'::geometry)
Planning time: 0.192 ms
Execution time: 282.758 ms

Probe mit &&(414ms)

SELECT COUNT(*) as value
FROM alasarr_social_mv  
WHERE the_geom_webmercator && 
  ST_MakeEnvelope(-410961,4920492,-402305,4926887,3857)

Aggregate  (cost=22535.97..22535.97 rows=1 width=0) (actual time=414.314..414.314 rows=1 loops=1)
  ->  Seq Scan on alasarr_social_mv  (cost=0.00..22444.94 rows=182050 width=0) (actual time=0.017..378.427 rows=178010 loops=1)
        Filter: (the_geom_webmercator && '0103000020110F0000010000000500000000000000441519C1000000002BC5524100000000441519C1000000C069CB524100000000048E18C1000000C069CB524100000000048E18C1000000002BC5524100000000441519C1000000002BC55241'::geometry)
        Rows Removed by Filter: 798260
Planning time: 0.134 ms
Execution time: 414.343 ms

PostGIS-Version

POSTGIS="2.2.2" GEOS="3.5.0-CAPI-1.9.0 r4084" PROJ="Rel. 4.8.0, 6 March 2012" GDAL="GDAL 1.11.0, released 2014/04/16" LIBXML="2.7.8" LIBJSON="UNKNOWN" (core procs from "2.2.2" need upgrade) RASTER (raster procs from "2.2.2" need upgrade)  alasarr 2 mins ago

2
Fügen Sie keine Screenshots von Text in die Frage ein. Können Sie diese als Code kopieren und einfügen? Ich kann sie nicht lesen, um dir zu helfen.
Evan Carroll

Getan. Ich denke, ist jetzt ein bisschen besser
leider

Ich habe versucht, Ihre neuen Abfragepläne in diese zurück zu portieren. Fühlen Sie sich frei, die Pläne zu aktualisieren, aber versuchen Sie, den Stil beizubehalten.
Evan Carroll

4
Schauen Sie sich diese Frage an . Der Operator && führt tatsächlich eine Begrenzungsrahmenabfrage durch, während ST_Intersects eine Begrenzungsrahmenabfrage verwendet, um zu bestimmen, welche Geometrien für den tatsächlichen Vergleich getestet werden sollen. Sie würden also erwarten, dass && schneller ist. Es ist jedoch wahrscheinlich, dass die Verwendung von ST_MakeEnvelope rechts von && den Abfrageplaner aus irgendeinem Grund dazu veranlasst, einen vollständigen Tabellenscan zu wählen (wie aus der Erläuterung hervorgeht). Versuchen Sie zunächst, die Geometrie in einem CTE zu erstellen, und prüfen Sie, ob Sie den Optimierer "täuschen" können.
John Powell

Du hast recht! es funktioniert in einem CTE
leider

Antworten:


16

Diese Art von Befund kommt ziemlich oft vor, und es ist ein bisschen dunkel, also lohnt es sich, es noch einmal zu wiederholen. Wenn Sie eine Geometrie innerhalb einer Funktion definieren, die sie verwendet, z. B. ST_Intersects oder && (die ST_Intersects unter der Haube verwendet), wählt der Abfrageplaner einen vollständigen Tabellenscan aus, da "es" keine Kenntnis über das Ergebnis der Geometrieerstellung hat Funktion, in diesem Fall ST_MakeEnvelope . Wenn Sie die Geometrie definieren, die Sie auf Schnittpunkte in einem CTE prüfen möchten, verarbeitet der Optimierer eine bekannte Größe und verwendet, falls verfügbar, einen räumlichen Index.

Schreiben Sie Ihre Anfrage also wie folgt um:

WITH test_geom (geom) AS 
   (SELECT ST_MakeEnvelope(-410961,4920492,-402305,4926887,3857))
  SELECT COUNT(*) as value
    FROM alasarr_social_mv mv, test_geom tg 
   WHERE ST_Intersects(mv.the_geom_webmercator, tg.geom)

verwendet jetzt einen räumlichen Index. Ebenso verwendet && jetzt einen Index, um nach einem Begrenzungsrahmen zu suchen, und sollte (obwohl ich nicht mit Ihren Daten testen kann) schneller als ST_Intersects sein.

Interessanterweise verwendet ST_Intersects in Ihrer Abfrage einen Bitmap-Scan-Index (kein Kernindex), während && keinen Index verwendet. Beide Abfragen sind mit dem CTE also schneller, aber && sollte jetzt schneller sein als ST_Intersects.

Es gibt weitere Erklärungen zu den Vorgängen in dieser Frage und ihren Antworten / Kommentaren .

BEARBEITEN : Um dies explizit zu machen, sehen Sie sich die Definition von ST_Intersects in postgis.sql an (die von CREATE EXTENSION postgisund im Contrib-Verzeichnis Ihrer Postgres-Installation aufgerufen wird ):

---- Inlines index magic
CREATE OR REPLACE FUNCTION ST_Intersects(geom1 geometry, geom2 geometry)
    RETURNS boolean
    AS 'SELECT $1 OPERATOR(&&) $2 AND _ST_Intersects($1,$2)'
    LANGUAGE 'sql' IMMUTABLE ;

einschließlich des Kommentars: Inlines Index Magic.


1
Ich glaube nicht, dass ST_Intersects && unter der Haube verwendet.
Evan Carroll

4
@EvanCarroll, überprüfe meine Bearbeitung. Schauen Sie sich postgis.sql an, wo die Funktionen definiert sind, und es sollte klarer sein.
John Powell
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.