Accélération des requêtes OpenGISMap PostGIS

12

J'ai des données OpenStreetMap pour les Pays-Bas chargées dans une base de données PostGIS (PostgreSQL 8.3 / PostGIS 1.3.3) en utilisant le schéma d'osmose . Cela signifie que toutes les balises sont stockées dans un champ hstore . En plus de l'index GIST que l'osmose crée sur le champ géométrique, j'ai créé un index GIST supplémentaire sur le champ tags.

En essayant d'interroger en utilisant à la fois une contrainte spatiale et une contrainte sur le champ des balises, je trouve que c'est plus lent que je ne le souhaiterais. Une requête comme celle-ci:

SELECT n.geom,n.tags,n.tstamp,u.name FROM nodes AS n 
  INNER JOIN users AS u ON n.user_id = u.id 
  WHERE tags->'man_made'='surveillance' 
  AND ST_Within(geom, ST_GeomFromText('POLYGON((4.0 52.0,5.0 52.0,5.0 53.0,4.0 53.0,4.0 52.0))',4326));

prend 22 secondes pour renvoyer 78 enregistrements.

Il y a environ 53 millions d'enregistrements dans ce tableau.

Existe-t-il un moyen d'accélérer considérablement cette opération? J'ai entendu dire que hstore est implémenté beaucoup mieux dans PostgreSQL 9, la mise à niveau serait-elle utile?

mvexel
la source
Comme cela semble être une question orientée base de données, je vous encourage à poser sur dba.stackexchange.com
jcolebrand
Mise à jour pour 2015 - PostGIS a apporté des améliorations significatives aux performances depuis que cette question a été posée, pensez donc à cela ainsi qu'à la mise à niveau de PostgreSQL.
Toby Speight

Réponses:

5

Une méthode serait de rechercher les balises qui vous intéressent et de placer ces enregistrements dans une nouvelle table. Vous n'aurez alors qu'à interroger la nouvelle table au lieu des 53 millions d'enregistrements. Si vous essayez de maintenir votre base de données à jour, vous pouvez exécuter cette requête chaque fois que vous obtenez de nouvelles données d'OSM.

jvangeld
la source
2
Plutôt que de créer une nouvelle table, vous pourriez envisager de créer une VUE à la place, de cette façon que vous "interrogez" est lié en direct à vos données source d'origine sans la duplication littérale des données.
RyanKDalton
7
Une vue n'améliorera pas nécessairement les performances des requêtes, sauf s'il s'agit d'une vue matérialisée ou équivalente (voir la question SO sur ce sujet). Je ne crois pas que Postgresql supporte directement les vues matérialisées , mais elles peuvent être implémentées à l'aide de déclencheurs.
Adam Armor
2
C'est la solution de contournement que j'utilise actuellement. Après une mise à jour des tables d'osmose, je recrée quelques tables optimisées pour les requêtes que je souhaite exécuter. Je pense simplement qu'il doit y avoir une meilleure façon. Le sujet des déclencheurs m'intrigue et comment vous pouvez les utiliser pour implémenter des vues matérielles. @Adam Armor, avez-vous une chance de partager quelques idées à ce sujet?
mvexel
4
@mvexel Jetez un œil à cet article wiki , qui couvre les bases des vues matérialisées et détaille comment les implémenter dans PostgreSQL.
Adam Armor
5

Vous pouvez essayer de créer un index pour votre colonne hstore,

CREATE INDEX nodes_tags_idx ON nodes USING GIST(tags)

puis utilisez l' ?opérateur pour limiter la requête aux seules lignes suivantes:

SELECT n.geom,n.tags,n.tstamp,u.name FROM nodes AS n 
  INNER JOIN users AS u ON n.user_id = u.id 
  WHERE tags ? 'man_made'
  AND tags->'man_made'='surveillance' 
  AND ST_Within(geom, ST_GeomFromText('POLYGON((4.0 52.0,5.0 52.0,5.0 53.0,4.0 53.0,4.0 52.0))',4326));
olt
la source
Merci! J'ai déjà créé cet index, sauf que je ne l'utilisais pas. Cela accélère seulement certaines opérations. Dans PostgreSQL 8.3 (que j'utilise), ce n'est que @> et? , dans 9.0 c'est @>,?,? & et? | .
mvexel
1
Pour mémoire, la requête utilisant l' ?opérateur a pris 48 secondes contre 88 secondes pour ma requête (je ne sais pas comment j'ai obtenu 72 secondes hier, peut-être que la machine faisait quelque chose de compliqué cette fois pendant que j'effectuais les requêtes). Donc, ce n'est toujours pas la performance que je recherche, mais j'ai acquis une meilleure compréhension du fonctionnement des index GIST sur les colonnes hstore. Je devrai toujours aller avec l'autre solution de création d'une vue matérialisée pour obtenir les performances que je souhaite.
mvexel
3

Les fonctions st_within et _st_within ne sont pas connues pour leur vitesse. L'opérateur && pourrait aider car il vérifiera la bbox au lieu de la géométrie

Vous pouvez essayer ce qui suit:

SELECT n.geom,n.tags,n.tstamp,u.name FROM nodes AS n 
  INNER JOIN users AS u ON n.user_id = u.id 
  WHERE tags ? 'man_made'
  AND tags->'man_made'='surveillance' 
  AND geom && ST_SetSRID('BOX3D(4 52,5 53)'::box3d,4326);

Pour plus de conseils sur les performances, consultez: http://postgis.refractions.net/docs/ch06.html

milovanderlinden
la source
2

Le problème avec votre requête est la tags->'man_made'='surveillance'clause. Cela oblige Postgres à développer les balises hstore et ne lui permet pas d'utiliser l'index. Si vous réécrivez ceci en utilisant @>(contient), cela permettra l'utilisation de l'index.

Parce que vous interrogez un rectangle, vous pouvez utiliser à la &&place de ST_Within. Cela aura un petit gain, car le ST_Within n'est pas si compliqué à évaluer, et ST_Within effectue implicitement une &&vérification.

Une augmentation supplémentaire de la vitesse consisterait à utiliser un index GIN sur les balises au lieu d'un index GIST. La construction des index GIN prend plus de temps mais est plus rapide.

La requête entière serait

SELECT n.geom,n.tags,n.tstamp,u.name FROM nodes AS n INNER JOIN users AS u ON n.user_id = u.id WHERE tags @> hstore('man_made', 'surveillance') AND geom && ST_GeomFromText('POLYGON((4.0 52.0,5.0 52.0,5.0 53.0,4.0 53.0,4.0 52.0))',4326);

Si vous savez que vous allez souvent interroger une balise particulière, vous pouvez créer un index partiel avec CREATE INDEX ON nodes ( tags->'man_made' ) WHERE (tags->'man_made' IS NOT NULL);.

Cela permettra à la condition WHERE tags->'man_made'='surveillance'd'utiliser l'index. Malheureusement, cet index ne peut pas aider les @>requêtes et les index GIN ou GIST ne peuvent pas aider les tags->'foo'requêtes, vous devez donc faire correspondre les requêtes aux index que vous avez.

Paul Norman
la source
Le conseil d'utilisation a tags @>hstore()considérablement amélioré ma requête, merci.
alphabetasoup
1

essayez plutôt ceci:

SELECT n.geom, n.tags, n.tstamp, u.name FROM nœuds AS n INNER JOIN utilisateurs AS u ON n.user_id = u.id WHERE tags @> 'man_made => surveillance' :: hstore AND ST_Within (geom , ST_GeomFromText ('POLYGON ((4.0 52.0,5.0 52.0,5.0 53.0,4.0 53.0,4.0 52.0))', 4326));

LR1234567
la source