Comment résoudre le problème de performances dans PostGIS ST_Intersects?

9

Je suis un débutant en postgis et j'ai un problème de performances de requête.

Cette ma requête:

SELECT DISTINCT ON (userid) userid ,ST_AsText(position), timestamp  
FROM table1 
WHERE ST_Intersects ( ST_GeomFromText('a multiypolygon geom goes here',4326),position) 
ORDER BY userid, timestamp desc

et le problème est que mon multipolygone comprend de TRÈS grands polygones (600 pages de long en document Word!) et il a fallu plus de 2 heures pour l'exécuter!

Existe-t-il un moyen d'optimiser ma requête ou d'utiliser une autre méthode?

Veuillez votre aide est grandement appréciée!

Sara
la source

Réponses:

8

Ce que vous devez faire est de placer votre grand multipolygone dans une table sous forme de polygones simples (avec ST_Dump) et de mettre un index dessus. Quelque chose comme:

CREATE TABLE big_polygon as
SELECT (ST_Dump( ST_GeomFromText('a multiypolygon geom goes here',4326))).geom as geom;

-- It is always great to put a primary key on the table
ALTER table big_polygon ADD Column gid serial PRIMARY KEY;

-- Create the index
CREATE INDEX idx_big_polygon_geom
on big_polygon
USING gist(geom);

-- To give the database some information about how the index looks
analyze big_polygon;

-- Then you go:
SELECT DISTINCT ON (userid) userid ,ST_AsText(position), timestamp  
FROM table1, big polygon WHERE ST_Intersects ( big_polygon.geom,position) 
ORDER BY userid, timestamp desc;

Cela devrait être beaucoup plus rapide pour plusieurs raisons.

Nicklas Avén
la source
Merci Nicklas pour cette excellente réponse. Désolé d'avoir oublié de mentionner que j'ai plusieurs polygones et qu'ils sont déjà stockés dans une table avec index. Mais je pensais que fournir directement les données géom serait plus rapide. Cependant, j'essaie comme vous le suggérez mais cela prend quand même très longtemps! une autre suggestion?
Sara
@Sara. Ok, donc vous avez essayé de diviser les multigénoémissions en géométries simples comme je le suggère avec ST_Dump?
Nicklas Avén
De combien de postes d'utilisateurs parlons-nous? Combien de gros polygones? Qu'obtenez-vous de SELECT ST_npoints (geom) de big_polygons_table ;?
Nicklas Avén
Désolé mon mauvais, permettez-moi d'expliquer plus sur mes tables pour le rendre plus clair pour vous: j'ai table1 qui comprend une colonne geom qui a environ 230 lignes et dans chaque ligne il y a un multipolygone (ils représentent des pays donc leur taille varie) , et ont l'index dans le col_geom. Tableau 2 qui comprend la colonne de position (points), l'horodatage, l'ID utilisateur et l'id (pk) et 3 index créés à l'aide de (position, horodatage, ID utilisateur) .Ce tableau est très grand, environ 103496003 lignes.Le nombre maximum de ST_npoints est 1440430 et le nombre minimum est 16. Je suis désolé si je vous ai dérouté mais j'ai vraiment besoin de votre aide! Merci
Sara
2

Cela dépend du type de qualité - précision dont vous avez besoin. Vous pouvez évidemment simplifier les polygones en utilisant: http://postgis.net/docs/ST_Simplify.html

Ce que j'ai souvent fait lors du développement de mon application SIG, c'était de réfléchir à la meilleure façon de minimiser les données. Par exemple. présélectionnez les polygones dans la zone de contour par exemple. - Selon le niveau de zoom, vous n'avez pas besoin de résultats ultra précis (st_simplify) etc.

J'espère que cela vous a aidé un peu!

Styp
la source
Merci Martin pour votre réponse rapide. Mon problème est que j'ai besoin que le résultat soit très précis, donc je pense que cette fonction ne m'aidera pas ici! mais merci pour la suggestion
Sara
0

Selon votre expertise postgres et / ou sql vous avez plusieurs options:

  1. analyser la requête via la commande EXPLAIN pour savoir si vous rencontrez un goulot d'étranglement particulier. Attention: parfois la sortie d'EXPLAIN peut être difficile à comprendre

  2. si vous vous attendez à ce que la plupart ou une partie importante des géométries du tableau 1 n'intersectent pas le multipolygone, vous pouvez essayer d'appliquer une condition préliminaire à un polygone plus simple (c'est-à-dire en cassant le multiploygon en morceaux plus petits), puis exécuter l'intersection de multipolygone plus lourde uniquement sur ces résultats. Voir ci-dessous pour un exemple.

  3. si et seulement si le CPU est le goulot d' étranglement (le serveur est intersections de calcul Stück) Je sourdement vous suggère de faire un plus grand, plus rapide, processeur plus puissant ou louer un haut-CPU unique instance de EC2 d'Amazon et détruis quand vous êtes terminé

Exemple de requête pour l'élément 2:

SELECT DISTINCT ON (st1.userid) st1.userid ,ST_AsText(st1.position), st1.timestamp  
FROM (
    select userid, position, timestamp from table1 
    WHERE ST_Intersects ( YOUR_MULTIPOL_BOUNDS_HERE,position)
) as st1 
WHERE ST_Intersects ( ST_GeomFromText('a multiypolygon geom goes     here',4326),st1.position) 
ORDER BY st1.userid, st1.timestamp desc

Pour améliorer les performances, vous pouvez également matérialiser temporairement la sous-sélection st1 en tant que table afin de pouvoir l'indexer.

@Nicklas a raison de souligner dans les commentaires que l'exemple de la suggestion 2 ne devrait pas aider. Il a raison, mais je pense que j'ai (en partie) raison aussi.

En fait, il semble qu'une question très similaire ait été posée (et répondue) en novembre dernier sur le postgis ML:

http://postgis.refractions.net/pipermail/postgis-users/2011-November/031344.html

et il s'avère que la suggestion est de réellement décomposer le polygone afin que l'index puisse filtrer le plus efficacement les fausses intersections qui seraient autrement déclenchées par une simple vérification des limites.

unicoletti
la source
la suggestion 2 ne devrait pas aider car c'est exactement ce que fait l'index. Donc, cette construction fera à nouveau la même chose.
Nicklas Avén
@ NicklasAvén vous avez raison, j'ai modifié la réponse
unicoletti
0

En utilisant ST_SubDivide()

Pour la version 2.2 de Postgis, vous pouvez utiliser ST_SubDivide.

ST_Subdivide - Renvoie un ensemble de géométries dans lesquelles aucune géométrie de l'ensemble ne dépasse le nombre de sommets spécifié.

setof geometry ST_Subdivide(geometry geom, integer max_vertices=256);

Vous pouvez aussi

  • utiliser une table temporaire
  • Un index

Ici, nous utilisons ST_SubDividepour décomposer le polygone en sous-polygones avec 10 sommets ou moins.

CREATE TEMP TABLE divided AS
SELECT ST_SubDivide(bigmultipolygon,10)::geometery AS t(geom);

CREATE INDEX divided_idx ON divided USING gist(geom);

alors

SELECT DISTINCT ON (userid) userid ,ST_AsText(position), timestamp  
FROM table1
JOIN divided AS d
  ON ST_Intersects( d.geom, position )
ORDER BY userid, timestamp desc;

Ne faites pas ce qui précède, cela introduit des erreurs d'arrondi

Réglage général

Consultez également la section intitulée Conseils sur les performances dans la documentation. Assurez-vous que vous êtes réglé correctement. Pensez à augmenter max_parallel_workers_per_gatherpour profiter de la parallélisation (actuellement désactivé par défaut).

Evan Carroll
la source