Chapter 4. Gestion des données

Table of Contents
4.1. Modèle de données spatiales
4.1.1. Géométrie OGC
4.1.2. SQL/MM Part 3 - Courbes
4.1.3. WKT et WKB
4.2. Type de données Geometry
4.2.1. PostGIS EWKB et EWKT
4.3. Type de données Geography
4.3.1. Création de tables géographiques
4.3.2. Utilisation des tables géographiques
4.3.3. Quand utiliser le type de données Geography
4.3.4. FAQ Geography avancée
4.4. Validation de la géométrie
4.4.1. Géométrie simple
4.4.2. Géométrie valide
4.4.3. Gestion de la validité
4.5. Systèmes de référence spatiale
4.5.1. Table SPATIAL_REF_SYS
4.5.2. Systèmes de référence spatiale définis par l'utilisateur
4.6. Tables spatiales
4.6.1. Créer une table spatiale
4.6.2. Vue GEOMETRY_COLUMNS
4.6.3. Enregistrement manuel des colonnes de géométrie
4.7. Chargement des données spatiales
4.7.1. Utilisation de SQL pour charger des données
4.7.2. Utilisation de l'utilitaire qui permet de charger des fichiers Shapefile
4.8. Extraction de données spatiales
4.8.1. Utiliser SQL pour extraire des données
4.8.2. Utilisation de Shapefile Dumper
4.9. Index spatiaux
4.9.1. Index GiST
4.9.2. Index BRIN
4.9.3. Index SP-GiST
4.9.4. Optimisation de l'utilisation de l'index

4.1. Modèle de données spatiales

4.1.1. Géométrie OGC

L'Open Geospatial Consortium (OGC) a développé le standard Simple Features Access (SFA) pour fournir un modèle de données géospatiales. Ce standard définit le type spatial Geometry, ainsi que les opérations pour manipuler et transformer des géométries, et permettre des tâches d'analyses spatiales. PostGIS implémente le modèle OGC Geometry sous forme de types PostgreSQL geometry et geography.

Geometry est un type abstrait. Les valeurs géométriques utilisent les sous-types concrets, qui représentent les diverses formes géométriques. Ces types incluent les types atomiques Point, LineString, LinearRing et Polygon, ainsi que les types de collections MultiPoint, MultiLineString, MultiPolygon et GeometryCollection. Le standard Simple Features Access - Part 1: Common architecture v1.2.1 ajoute les sous-types pour les structures PolyhedralSurface, Triangle et TIN.

Geometry représente des formes dans le plan cartésien en 2 dimensions. Les types PolyhedralSurface, Triangle, et TIN peuvent également représenter des formes en 3 dimensions. La taille et la localisation des formes sont spécifiées par leurs coordonnées. Chaque coordonnées a une dimension X et une Y, qui déterminent sa position sur le plan. Les formes sont construites à partir de points ou de segments. Les points sont spécifiés par une seul coordonnée ; les segments par deux coordonnées.

Les coordonnées peuvent inclure des valeurs pour les dimensions optionnelles Z et M. La dimension Z est souvent utilisée pour représenter l'élévation. La dimension M contient une mesure, qui représente par exemple le temps ou une distance. Si la dimension Z ou M est présente pour une valeur géométrique, elle doit être définie pour tous les points de la géométrie. Si une géométrie a une dimension Z ou M, la dimension de la coordonnée est 3D ; si elle a à la fois les dimension Z et M, la dimension de la coordonnée est 4D.

Les valeurs géométriques sont associées à un système de coordonnées de référence (SCR, ou en anglais spatial reference system, SRS), qui indique dans quel système de coordonnées les valeurs sont définies. Le SCR est identifié par un identifiant appelé SRID. Les unités sur les axes X et Y sont déterminées par ce système de coordonnées de référence. Dans un système planaire, les coordonnées X et Y représentent les distances respectivement selon l'Est et le Nord. Dans un système géodésique elles représentent la longitude et la latitude. L'identifiant SRID 0 représente un plan cartésien infini, sans unité sur ses axes. Voir Section 4.5, “Systèmes de référence spatiale”.

La dimension d'une géométrie est une propriété des types géométriques. Les types Point ont une dimension 0, les types linéaires ont une dimension 1, et les types polygonaux ont une dimension 2. Les collections ont la dimension de leur élément de plus grande dimension.

Une valeur géométrique peut être vide. Une valeur vide ne contient aucun vertex (pour les types de géométriques atomiques) ou aucun élément (pour les collections).

Une propriété important des valeurs géométriques est leur emprise spatiale (extent en anglais) ou leur boîte englobante (bounding box en anglais), que le modèle OGC nomme enveloppe (envelope). La boîte englobante est la boîte 2D ou 3D qui contient les coordonnées d'une géométrie. C'est une façon efficace de représenter l'emprise d'une géométrie dans un espace et de tester comment deux géométries interagissent.

Le modèle de géométrie permet d'évaluer les relations topologiques, telles que décrites dans Section 5.1.1, “Modèle à 9 intersections dimensionnellement étendu”. Pour supporter cela, les concepts de intérieur (interior en anglais), frontière (boundary en anglais) et extérieur (exterior en anglais) sont définis pour tous les types de géométries. Les géométries sont topologiquement fermées, donc elle contiennent toujours leur frontière. La dimension de la géométrie de la frontière est la dimension de la géométrie moins un.

Le modèle de géométrie OGC définie des règles de validité pour chaque type géométrique. Ces règles permettent de s'assurer que les valeurs géométriques représentent des situations réalistes (e.g. il est possible de définir un polygone avec un trou à l'extérieur, mais cela n'a pas de sens au niveau géométrique, et est donc invalide). PostGIS permet de stocker et de manipuler des valeurs géométriques invalides, ceci permet de les détecter et de les corriger si besoin. Voir Section 4.4, “Validation de la géométrie”

4.1.1.1. Point

Un objet de type Point est une géométrie de dimension 0, qui représente un seul point dans l'espace.

POINT (1 2)
POINT Z (1 2 3)
POINT ZM (1 2 3 4)

4.1.1.2. LineString

Le type LineString est une ligne, de dimension 1, formée par une séquence de segments linéaires contigus. Chaque segment est défini par deux points, l'extrémité d'un segment étant le point de départ du segment suivant. Un LineString valide au sens OGC a soit zéro, soit deux points ou plus, mais PostGIS permet d'avoir des LineStrings avec un seul point. LineStrings peuvent se croiser (auto-intersection). Un LineString peut être fermé si les points de début et fin sont les mêmes. Un LineString est dit simple s'il ne s'auto-intersecte pas.

LINESTRING (1 2, 3 4, 5 6)

4.1.1.3. LinearRing

Le type LinearRing définit un LineString qui est à la fois fermé et simple. Autrement dit, le premier et dernier points doivent être égaux, et la ligne ne doit pas s'auto-intersecter.

LINEARRING (0 0 0, 4 0 0, 4 4 0, 0 4 0, 0 0 0)

4.1.1.4. Polygon

Un polygone, de type Polygon est une région d'un plan, de dimension 2, délimité par une frontière extérieure (la coquille, shell en anglais) et zéro, une ou plusieurs frontières intérieures (trous, holes en anglais). Chaque frontière est un LinearRing.

POLYGON ((0 0 0,4 0 0,4 4 0,0 4 0,0 0 0),(1 1 0,2 1 0,2 2 0,1 2 0,1 1 0))

4.1.1.5. MultiPoint

Le type MultiPoint est une collection de Points.

MULTIPOINT ( (0 0), (1 2) )

4.1.1.6. MultiLineString

Le type MultiLineString est une collection de LineStrings. Un MultiLineString est fermé si tous ses éléments sont fermés.

MULTILINESTRING ( (0 0,1 1,1 2), (2 3,3 2,5 4) )

4.1.1.7. MultiPolygon

Un MultiPolygon est une collection de Polygons, non superposés et non adjacents. Les polygones de la collection peuvent se toucher, mais uniquement en un nombre fini de points.

MULTIPOLYGON (((1 5, 5 5, 5 1, 1 1, 1 5)), ((6 5, 9 1, 6 1, 6 5)))

4.1.1.8. GeometryCollection

Le type GeometryCollection représente une collection hétérogène de géométries (i.e. de types différents).

GEOMETRYCOLLECTION ( POINT(2 3), LINESTRING(2 3, 3 4))

4.1.1.9. PolyhedralSurface

Le type PolyhedralSurface modélise une surface polyédrique, sous la forme d'une collection de faces qui partagent des arêtes. Chaque face est un Polygon plan. Si les coordonnées du Polygon ont une dimension Z, alors la surface est de dimension 3.

POLYHEDRALSURFACE Z (
  ((0 0 0, 0 0 1, 0 1 1, 0 1 0, 0 0 0)),
  ((0 0 0, 0 1 0, 1 1 0, 1 0 0, 0 0 0)),
  ((0 0 0, 1 0 0, 1 0 1, 0 0 1, 0 0 0)),
  ((1 1 0, 1 1 1, 1 0 1, 1 0 0, 1 1 0)),
  ((0 1 0, 0 1 1, 1 1 1, 1 1 0, 0 1 0)),
  ((0 0 1, 1 0 1, 1 1 1, 0 1 1, 0 0 1)) )

4.1.1.10. Triangle

Un Triangle est un polygone définit par trois sommets non colinéaires. Un Triangle étant un Polygon, et donc est fermé, il est définit par quatre coordonnées, la première et la dernière étant égales.

TRIANGLE ((0 0, 0 9, 9 0, 0 0))

4.1.1.11. TIN

Un TIN est une collection de Triangles non superposés, représentant un réseau irrégulier triangulé (Triangulated Irregular Network).

TIN Z ( ((0 0 0, 0 0 1, 0 1 0, 0 0 0)), ((0 0 0, 0 1 0, 1 1 0, 0 0 0)) )

4.1.2. SQL/MM Part 3 - Courbes

La norme ISO/IEC 13249-3 SQL Multimedia - Spatial (SQL/MM) étend l'OGC SFA pour définir des sous-types de géométrie contenant des courbes avec des arcs circulaires. Les types SQL/MM prennent en charge les coordonnées 3DM, 3DZ et 4D.

[Note]

Toutes les comparaisons en flottant dans l'implémentation de SQL-MM sont effectuées avec une tolérance spécifiée, actuellement 1E-8.

4.1.2.1. CircularString

CircularString est le type de courbe de base, similaire à LineString dans le monde linéaire. Un segment d'arc unique est spécifié par trois points : les points de départ et d'arrivée (premier et troisième) et un autre point de l'arc. Pour spécifier un cercle fermé, les points de départ et d'arrivée sont les mêmes et le point central est le point opposé sur le diamètre du cercle (qui est le centre de l'arc). Dans une séquence d'arcs, le point final de l'arc précédent est le point de départ de l'arc suivant, tout comme les segments d'une LineString. Cela signifie qu'une CircularString doit avoir un nombre impair de points supérieur à 1.

CIRCULARSTRING(0 0, 1 1, 1 0)

CIRCULARSTRING(0 0, 4 0, 4 4, 0 4, 0 0)

4.1.2.2. CompoundCurve

Une CompoundCurve est une courbe continue unique qui peut contenir à la fois des segments d'arc de cercle et des segments linéaires. Cela signifie qu'en plus d'avoir des composantes bien formées, le point final de chaque composante (sauf la dernière) doit coïncider avec le point de départ de la composante suivante.

COMPOUNDCURVE( CIRCULARSTRING(0 0, 1 1, 1 0),(1 0, 0 1))

4.1.2.3. CurvePolygon

Un CurvePolygon est semblable à un polygone, avec un anneau extérieur et zéro ou plusieurs anneaux intérieurs. La différence est qu'un anneau peut être une CircularString ou une CompoundCurve ainsi qu'une LineString.

Depuis PostGIS 1.4, PostGIS prend en charge les courbes composées dans un polygone de courbe.

CURVEPOLYGON(
  CIRCULARSTRING(0 0, 4 0, 4 4, 0 4, 0 0),
  (1 1, 3 3, 3 1, 1 1) )

Exemple : Un PolygoneCourbe dont l'enveloppe est définie par une CompoundCurve contenant une CircularString et une LineString, et dont le trou est défini par une CircularString.

CURVEPOLYGON(
  COMPOUNDCURVE( CIRCULARSTRING(0 0,2 0, 2 1, 2 3, 4 3),
                 (4 3, 4 5, 1 4, 0 0)),
  CIRCULARSTRING(1.7 1, 1.4 0.4, 1.6 0.4, 1.6 0.5, 1.7 1) )

4.1.2.4. MultiCurve

Une MultiCurve est un ensemble de courbes qui peuvent inclure des LineStrings, des CircularStrings ou des CompoundCurves.

MULTICURVE( (0 0, 5 5), CIRCULARSTRING(4 0, 4 4, 8 4))

4.1.2.5. MultiSurface

Une MultiSurface est un ensemble de surfaces, qui peuvent être des polygones (linéaires) ou des polygones courbes.

MULTISURFACE(
  CURVEPOLYGON(
    CIRCULARSTRING( 0 0, 4 0, 4 4, 0 4, 0 0),
    (1 1, 3 3, 3 1, 1 1)),
  ((10 10, 14 12, 11 10, 10 10), (11 11, 11.5 11, 11 11.5, 11 11)))

4.1.3. WKT et WKB

La spécification OGC SFA définit deux formats pour représenter des valeurs géométriques : Well-Known Text (WKT) et Well-Known Binary (WKB). Ces deux formats incluent les informations sur le type d'objet et sur les coordonnées qui le définissent.

Well-Known Text (WKT) fournit un standard pour représenter de façon textuelle des données spatiales. Voici quelques exemples de représentations WKT :

  • POINT(0 0)

  • POINT Z (0 0 0)

  • POINT ZM (0 0 0 0)

  • POINT EMPTY

  • LINESTRING(0 0,1 1,1 2)

  • LINESTRING EMPTY

  • POLYGON((0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1))

  • MULTIPOINT((0 0),(1 2))

  • MULTIPOINT Z ((0 0 0),(1 2 3))

  • MULTIPOINT EMPTY

  • MULTILINESTRING((0 0,1 1,1 2),(2 3,3 2,5 4))

  • MULTIPOLYGON(((0 0,4 0,4 4,0 4,0 0),(1 1,2 1,2 2,1 2,1 1)), ((-1 -1,-1 -2,-2 -2,-2 -1,-1 -1)))

  • GEOMETRYCOLLECTION(POINT(2 3),LINESTRING(2 3,3 4))

  • GEOMETRYCOLLECTION EMPTY

Des méthodes d'entrée/sortie en WKT sont fournies via les fonctions ST_AsText et ST_GeomFromText :

text WKT = ST_AsText(geometry);
geometry = ST_GeomFromText(text WKT, SRID);

Par exemple, une requête pour créer et insérer une objet spatial sous forme de WKT et avec un SRID :

INSERT INTO geotable ( geom, name )
  VALUES ( ST_GeomFromText('POINT(-126.4 45.32)', 312), 'A Place');

Well-Known Binary (WKB) fournit un moyen portable et sans perte de précision pour représenter des données spatiales sous la forme de données binaires (tableau d'octets). Voici quelques exemples de représentations WKB :

  • WKT : POINT(1 1)

    WKB : 0101000000000000000000F03F000000000000F03

  • WKT : LINESTRING (2 2, 9 9)

    WKB : 0102000000020000000000000000000040000000000000004000000000000022400000000000002240

Des méthodes d'entrée/sortie en WKB sont fournies via les fonctions ST_AsBinary et ST_GeomFromWKB :

bytea WKB = ST_AsBinary(geometry);
geometry = ST_GeomFromWKB(bytea WKB, SRID);

Par exemple, une requête pour créer et insérer une objet spatial sous forme de WKB :

INSERT INTO geotable ( geom, name )
  VALUES ( ST_GeomFromWKB('\x0101000000000000000000f03f000000000000f03f', 312), 'A Place');

4.2. Type de données Geometry

PostGIS implémente le modèle Simple Features de l'OGC via un type PostgreSQL geometry. Ce type représente tous les sous-types de géométries en utilisant un type interne (voir GeometryType et ST_GeometryType). Cela permet de modéliser les entités spatiales comme lignes de tables qui contiennent une colonne de type geometry.

Le type geometry est opaque, ce qui veut dire que tout accès est fait en appelant des fonctions sur les valeurs géométriques. Des fonctions permettent la création d'objets géométriques, l'accès et la mise à jour des champs internes, ainsi que le calcul de nouvelles valeurs géométriques. PostGIS supporte toutes les fonctions spécifiées par la spécification OGC Simple feature access - Part 2: SQL option (SFS), ainsi que de nombreuses autres. voir Chapter 7, Référence PostGIS pour une liste complète des fonctions disponibles.

[Note]

PostGIS respecte le standard SFA en préfixant toutes les fonctions spatiales par "ST_". Initialement, cela voulait dire "Spatial and Temporal" (Spatial et Temporel), mais l'aspect temporel du standard n'a pas été développé. À la place, ceci peut être interprété comme "Spatial Type" (Type Spatial).

La standard SFA spécifie que les objets spatiaux doivent inclure un identifiant de système de coordonnées de référence (SRID). Ce SRID est obligatoire lors de la création d'objets spatiaux pour l'insertion dans la base de données (mais peut être défini par défaut à 0). Voir ST_SRID et Section 4.5, “Systèmes de référence spatiale”

Pour optimiser les requêtes sur les géométries, PostGIS définit plusieurs types d'index spatiaux, ainsi que des opérateurs spatiaux pour les utiliser. Voir Section 4.9, “Index spatiaux” et Section 5.2, “Utilisation des index spatiaux” pour plus d'informations.

4.2.1. PostGIS EWKB et EWKT

Les spécifications OGC SFA ne supportaient initialement que les géométries 2D, et le SRID de la géométrie n'est pas inclut dans les représentations d'entrée/sortie. La spécification OGC SFA 1.2.1 (qui est alignée avec le standard ISO 19125) ajoute le support pour la 3D (ZYZ) et les mesures (XYM et XYZM), mais n'inclut toujours pas la valeur du SRID.

À cause de ces limitations, PostGIS définit les formats étendus EWKB ((Extended Well-Known Binary) et EWKT (Extended Well-Known Text). Ils supportent la 3D (XYZ et XYM) et 4D (XYZM) et incluent l'information de SRID. Le format EWKB incluant toutes les informations de la géométrie, cela permet à PostGIS d'utiliser ce format pour les enregistrements (e.g. dans les fichiers DUMP).

EWKB et EWKT sont utilisés pour les "formes canoniques" des objets spatiaux de PostGIS. En tant qu'entrée, la forme canonique pour les données binaires est EWKB ; pour les données textuelles EWKB et EWKT sont tous deux acceptés. Cela permet de créer des valeurs géométriques en transtypant une valeur textuelle en HEXEWKB ou EWKT vers une valeur géométrique en utilisant ::geometry. Pour la sortie, la forme canonique pour les données binaires est EWKB et HEXEWKB (hex-encoded EWKB) pour les données textuelles.

Par exemple, cette requête créé une géométrie en transtypant depuis une chaîne de caractères contenant du EKWT, et retourne sa valeur sous sa forme canonique en HEXEWKB :

SELECT 'SRID=4;POINT(0 0)'::geometry;
  geometry
  ----------------------------------------------------
  01010000200400000000000000000000000000000000000000

La sortie PostGIS EWKT a quelques différences avec le OGC WKT :

  • Pour les géométries 3DZ, le qualificatif Z est omis :

    OGC : POINT Z (1 2 3)

    EWKT : POINT (1 2 3)

  • Pour les géométries 3DM, le qualificatif M est inclus :

    OGC : POINT M (1 2 3)

    EWKT : POINTM (1 2 3)

  • Pour les géométries 4D, le qualificatif ZM est omis :

    OGC : POINT ZM (1 2 3 4)

    EWKT : POINT (1 2 3 4)

EWKT évite de sur-spécifier les dimensions et ainsi éviter les inconsistances possibles avec le format OGC/ISO, comme :

  • POINT ZM (1 1)

  • POINT ZM (1 1 1)

  • POINT (1 1 1 1)

[Caution]

Les formats étendus PostGIS sont des sur-ensembles des formats OGC, donc les représentations valides WKB/WKT sont aussi des représentations EWKB/EWKT valides. Cependant, cela pourrait changer à l'avenir, si l'OGC définit un format qui rentrerait en conflit avec la définition de PosGIS. Vous ne devriez donc PAS vous appuyer sur cette compatibilité !

Voici quelques exemples de représentations d'objets spatiaux sous forme EWKT :

  • POINT(0 0 0) -- XYZ

  • SRID=32632;POINT(0 0) -- XY avec SRID

  • POINTM(0 0 0) -- XYM

  • POINT(0 0 0 0) -- XYZM

  • SRID=4326;MULTIPOINTM(0 0 0,1 2 1) -- XYM avec SRID

  • MULTILINESTRING((0 0 0,1 1 0,1 2 1),(2 3 1,3 2 1,5 4 1))

  • POLYGON((0 0 0,4 0 0,4 4 0,0 4 0,0 0 0),(1 1 0,2 1 0,2 2 0,1 2 0,1 1 0))

  • MULTIPOLYGON(((0 0 0,4 0 0,4 4 0,0 4 0,0 0 0),(1 1 0,2 1 0,2 2 0,1 2 0,1 1 0)),((-1 -1 0,-1 -2 0,-2 -2 0,-2 -1 0,-1 -1 0)))

  • GEOMETRYCOLLECTIONM( POINTM(2 3 9), LINESTRINGM(2 3 4, 3 4 5) )

  • MULTICURVE( (0 0, 5 5), CIRCULARSTRING(4 0, 4 4, 8 4) )

  • POLYHEDRALSURFACE( ((0 0 0, 0 0 1, 0 1 1, 0 1 0, 0 0 0)), ((0 0 0, 0 1 0, 1 1 0, 1 0 0, 0 0 0)), ((0 0 0, 1 0 0, 1 0 1, 0 0 1, 0 0 0)), ((1 1 0, 1 1 1, 1 0 1, 1 0 0, 1 1 0)), ((0 1 0, 0 1 1, 1 1 1, 1 1 0, 0 1 0)), ((0 0 1, 1 0 1, 1 1 1, 0 1 1, 0 0 1)) )

  • TRIANGLE ((0 0, 0 10, 10 0, 0 0))

  • TIN( ((0 0 0, 0 0 1, 0 1 0, 0 0 0)), ((0 0 0, 0 1 0, 1 1 0, 0 0 0)) )

Des méthodes d'entrée/sortie sont fournies via les fonctions suivantes :

bytea EWKB = ST_AsEWKB(geometry);
text EWKT = ST_AsEWKT(geometry);
geometry = ST_GeomFromEWKB(bytea EWKB);
geometry = ST_GeomFromEWKT(text EWKT);

Par exemple, une requête pour créer et insérer une objet spatial sous forme de EWKT :

INSERT INTO geotable ( geom, name )
  VALUES ( ST_GeomFromEWKT('SRID=312;POINTM(-126.4 45.32 15)'), 'A Place' )

4.3. Type de données Geography

Le type de données PostGIS geography permet le support des entités spatiales utilisant un système de coordonnées géographique (parfois appelé géodésique, ou "latitude/longitude" ou "longitude/latitude"). Les coordonnées géographiques sont des coordonnées sphériques, exprimées en unités d'angle (degrés).

Le type geometry de PostGIS est lié à un plan. Ainsi, le chemin le plus court entre deux points sur un plan est la ligne droite. Les fonctions sur les types geometry (aires, distances, intersections, etc.) sont donc calculées en utilisant des lignes droites et les mathématiques cartésiennes. Cela permet des implémentations plus faciles et plus rapides à exécuter, mais cela devient imprécis lorsque la rotondité de la Terre entre en jeu.

Le type PostGIS geography repose sur un modèle sphérique. Le chemin le plus court entre deux points sur une sphère est l'arc de cercle. Les fonctions sur les types geography (aires, distances, intersections, etc.) sont donc calculées en utilisant des arcs de cercle sur une sphère. En prenant en compte la rotondité de la Terre, ces fonctions permettent d'avoir une meilleure précision.

Les mathématiques utilisées pour les calculs étant plus compliquées, moins de fonctions sont définies pour le type geography que pour le type geometry. De nouveaux algorithmes sont ajoutés au fur et à mesure des versions de PostGIS, donc le support du type geography s'étend petit à petit. Si une fonction n'est pas disponible, il est toutefois possible de convertir un type geography en geometry puis vice-versa.

Comme le type geometry, les données géographiques sont liées à un identifiant de système de coordonnées de référence (SRID). Tout système géodésique (reposant sur longitude/latitude) peut être utilisé, tant qu'il défini dans la table spatial_ref_sys. (Avant PostGIS 2.2, le type geography ne supportait que le SCR WGS 84 (SRID:4326)). Vous pouvez ajouter votre propre SCR géodésique, comme décrit dans Section 4.5.2, “Systèmes de référence spatiale définis par l'utilisateur”.

Pour tous les systèmes de coordonnées de référence, les unités des valeurs retournées par les fonctions de mesure (e.g. ST_Distance, ST_Length, ST_Perimeter, ST_Area) et le paramètre de distance de ST_DWithin sont en mètres.

4.3.1. Création de tables géographiques

Vous pouvez créer une table pour stocker des données géographiques en utilisant la requête SQL CREATE TABLE, avec une colonne de type geography. L'exemple suivant créé une table avec une colonne géographique pour stocker des lignes 2D dans un SCR géodésique WGS84 (SRID 4326) :

CREATE TABLE global_points (
    id SERIAL PRIMARY KEY,
    name VARCHAR(64),
    location geography(POINT,4326)
  );

Le type geography supporte deux modificateurs de type :

  • le modificateur de type spatial restreint le type de formes et dimensions de la colonne. Les valeurs permises pour le type spatial sont : POINT, LINESTRING, POLYGON, MULTIPOINT, MULTILINESTRING, MULTIPOLYGON, GEOMETRYCOLLECTION. Le type geography ne supporte pas les CURVEs, TINS, ni POLYHEDRALSURFACEs. Le modificateur permet de restreindre la dimension, en ajoutant les suffixes : Z, M ou ZM. Par exemple, un modificateur 'LINESTRINGM' permet uniquement de stocker des LineStrings en 3D, et traite la troisième dimension comme une mesure. De façon similaire, 'POINTZM' limite aux données 4D (XYZM).

  • le modificateur SRID restreint à un SCR spécifique. Si omis, le SRID 4326 (WGS84 géodésique) est utilisé, et tous les calculs sont effectués en utilisant WGS84.

Exemples de création de tables utilisant des colonnes géographiques :

  • Création d'une table avec une géographie POINT 2D avec le SRID par défaut 4326 (WGS84 longitude/latitude) :

    CREATE TABLE ptgeogwgs(gid serial PRIMARY KEY, geog geography(POINT) );
  • Création d'une table avec une géographie POINT 2D dans le CRS NAD83 longlat :

    CREATE TABLE ptgeognad83(gid serial PRIMARY KEY, geog geography(POINT,4269) );
  • Création d'une table avec une géographie POINT 3D (XYZ) avec le SCR explicite 4326 :

    CREATE TABLE ptzgeogwgs84(gid serial PRIMARY KEY, geog geography(POINTZ,4326) );
  • Création d'une table avec une géographie LINESTRING 2D avec le SRID par défaut 4326 :

    CREATE TABLE lgeog(gid serial PRIMARY KEY, geog geography(LINESTRING) );
  • Création d'une table avec une géographie POLYGON 2D avec le SRC 4267 (NAD 1927 long lat) :

    CREATE TABLE lgeognad27(gid serial PRIMARY KEY, geog geography(POLYGON,4267) );

Les colonnes géographiques sont enregistrées dans la vue système geography_columns. Vous pouvez effectuer un requête sur la vue geography_columns et vérifier que la table est bien listée :

SELECT * FROM geography_columns;

La création d'index spatiaux sur les colonnes de type geography fonctionne de la même manière qu'avec le type geometry. PostGIS va prendre en compte que le type de la colonne est GEOGRAPHY et créer un index sphérique au lieu d'un index planaire utilisé pour GEOMETRY.

-- Index the test table with a spherical index
CREATE INDEX global_points_gix ON global_points USING GIST ( location );

4.3.2. Utilisation des tables géographiques

Vous pouvez insérer des données dans des tables géographiques de la même façon qu'avec les géométries. Les données géométriques seront automatiquement transtypées en type geography si le SRID des données est 4326. Les formats EWKT et EWKB peuvent aussi être utilisés pour spécifier les valeurs géographiques.

-- Add some data into the test table
INSERT INTO global_points (name, location) VALUES ('Town', 'SRID=4326;POINT(-110 30)');
INSERT INTO global_points (name, location) VALUES ('Forest', 'SRID=4326;POINT(-109 29)');
INSERT INTO global_points (name, location) VALUES ('London', 'SRID=4326;POINT(0 49)');

Tout CRS géodésique (longitude/latitude) disponible dans la table spatial_ref_sys peut être utilisé comme SRID d'une géographie. L'utilisation d'un CRS non géodésique provoquera une erreur.

-- NAD 83 lon/lat
SELECT 'SRID=4269;POINT(-123 34)'::geography;
                    geography
----------------------------------------------------
 0101000020AD1000000000000000C05EC00000000000004140
-- NAD27 lon/lat
SELECT 'SRID=4267;POINT(-123 34)'::geography;
                    geography
----------------------------------------------------
 0101000020AB1000000000000000C05EC00000000000004140
-- NAD83 UTM zone meters - gives an error since it is a meter-based planar projection
SELECT 'SRID=26910;POINT(-123 34)'::geography;

ERROR:  Only lon/lat coordinate systems are supported in geography.

Les requêtes et les fonctions de mesure utilisent le mètre comme unité. Les paramètres de distance doivent être exprimés en mètres, et les valeurs de retours seront également en mètres (ou en mètres carré pour les surfaces).

-- A distance query using a 1000km tolerance
SELECT name FROM global_points WHERE ST_DWithin(location, 'SRID=4326;POINT(-110 29)'::geography, 1000000);

Vous pouvez vérifier la puissance des géographies en calculant à quel point un avion s'approche de Reykjavik (POINT(-21.96 64.15)) lors d'un trajet en arc de cercle depuis Seattle à Londres (LINESTRING(-122.33 47.606, 0.0 51.5)) (voir la route).

Le type geography donne la plus petite distance réelle de 122,235 km sur la sphère entre Reykjavik et l'arc de cercle entre Seattle et Londres.

-- Distance calculation using GEOGRAPHY
SELECT ST_Distance('LINESTRING(-122.33 47.606, 0.0 51.5)'::geography, 'POINT(-21.96 64.15)'::geography);
   st_distance
-----------------
 122235.23815667

Le type geometry quant à lui calcule la distance cartésienne entre Reykjavik et la ligne droite entre Seattle et Londres, telle qu'elle serait tracée sur un plan. Cette distance n'a pas de sens réel, d'autant que l'unité du résultat est techniquement en degrés, mais que le résultat ne correspond à aucune différence angulaire entre les points, donc même considérer le résultat comme des degrés serait faux.

-- Distance calculation using GEOMETRY
SELECT ST_Distance('LINESTRING(-122.33 47.606, 0.0 51.5)'::geometry, 'POINT(-21.96 64.15)'::geometry);
      st_distance
--------------------
 13.342271221453624

4.3.3. Quand utiliser le type de données Geography

Le type de données geography permet de stocker des données en utilisant les coordonnées longitude/latitude, mais cela a un prix : il y a moins de fonctions disponibles sur le type GEOGRAPHY que sur le type GEOMETRY, et les fonctions disponibles prendront plus de temps CPU pour s'exécuter.

Le type de données à choisir devrait être déterminé par la zone de travail de l'application que vous construisez. Est-ce que vos données s'étendront sur l'ensemble du globe ou sur un continent, ou bien est-ce qu'elle seront locales, comme une région, un département ou une ville ?

  • Si vous données sont limitées à une petite zone, utiliser un SCR adéquat et le type GEOMETRY est la meilleure solution, à la fois en terme de performances que de fonctionnalités disponibles.

  • Si vos données s'étendent sur le monde entier ou couvrent un continent, le type GEOGRAPHY peut vous permettre de construire votre application sans trop vous soucier des projections. Vous pouvez stocker vos données en utilisant les coordonnées longitude/latitude, et utiliser les fonctions définies sur les GEOGRAPHY.

  • Si vous n'êtes pas à l'aise avec les projections, que vous ne souhaitez pas approfondir le sujet, et que vous êtes prêts à accepter les limitations sur les fonctionnalités offertes par GEOGRAPHY, alors ce peut être plus facile d'utiliser GEOGRAPHY au lieu de GEOMETRY. Chargez vos données en longitude/latitude et partez de là.

Référez-vous à Section 12.11, “Matrice d'aide aux fonctions de PostGIS” pour comparer les supports Geography et Geometry. Pour avoir un résumé des fonctions géographiques disponibles, référez-vous à Section 12.4, “Fonctions d'aide au type geography de PostGIS”

4.3.4. FAQ Geography avancée

4.3.4.1. Les calculs sont-ils faits sur la sphère ou sur la sphéroïde ?
4.3.4.2. Qu'en est-il de la ligne de changement de date et des pôles ?
4.3.4.3. Quel est l'arc le plus long que vous puissiez traiter ?
4.3.4.4. Pourquoi est-il si lent de calculer la superficie de l'Europe / de la Russie / insérer une grande région géographique ici ?

4.3.4.1.

Les calculs sont-ils faits sur la sphère ou sur la sphéroïde ?

Par défaut, tous les calculs sur les distances et les surfaces sont effectués sur la sphéroïde. Les résultats des calculs sur les petites zones devraient coïncider avec les résultats des calculs planaire en utilisant les projections locales adéquates. Sur de plus grandes zones, les calculs sphéroïdaux seront plus précis que ceux effectués sur un plan projeté.

Toutes les fonctions géographiques ont une option pour calculer sur une sphère, en passant comme tout dernier paramètre booléen 'FALSE'. Ceci améliorera les performances des calculs, en particulier pour les géométries très simples.

4.3.4.2.

Qu'en est-il de la ligne de changement de date et des pôles ?

Tous les calculs omettent les concepts de ligne de changement de date et de pôles. Les coordonnées étant sphériques (longitude/latitude), une forme traversant la ligne de changement de date n'est, d'un point de vue calculs, pas différente de toute autre forme.

4.3.4.3.

Quel est l'arc le plus long que vous puissiez traiter ?

Nous utilisons les arcs de grand cercle comme "ligne d'interpolation" entre deux points. Cela signifie que deux points quelconques sont en fait reliés de deux manières différentes, selon la direction dans laquelle vous vous déplacez le long du grand cercle. Tout notre code suppose que les points sont reliés par le *plus court* des deux chemins le long du grand cercle. Par conséquent, les formes qui ont des arcs de plus de 180 degrés ne seront pas correctement modélisées.

4.3.4.4.

Pourquoi est-il si lent de calculer la superficie de l'Europe / de la Russie / insérer une grande région géographique ici ?

Parce que le polygone est vraiment énorme ! Les grandes zones sont néfastes pour deux raisons : leurs limites sont énormes, de sorte que l'index a tendance à tirer l'élément, quelle que soit la requête que vous exécutez ; le nombre de sommets est énorme, et les tests (distance, confinement) doivent parcourir la liste des sommets au moins une fois et parfois N fois (N étant le nombre de sommets dans l'autre élément candidat).

Comme pour la GÉOMÉTRIE, nous vous recommandons, lorsque vous avez de très grands polygones, mais que vous effectuez des requêtes sur de petites zones, de "dénormaliser" vos données géométriques en morceaux plus petits, de sorte que l'index puisse effectivement interroger des parties de l'objet et que les requêtes n'aient pas à extraire l'objet entier à chaque fois. Veuillez consulter la documentation de la fonction ST_Subdivide. Ce n'est pas parce que vous *pouvez* stocker toute l'Europe dans un polygone que vous *devriez* le faire.

4.4. Validation de la géométrie

PostGIS est conforme à la spécification Simple Features de l'Open Geospatial Consortium (OGC). Cette norme définit les concepts de géométrie comme étant simple et valide. Ces définitions permettent au modèle géométrique Simple Features de représenter les objets spatiaux d'une manière cohérente et non ambiguë qui permet un calcul efficace. (Remarque : l'OGC SF et SQL/MM ont les mêmes définitions pour simple et valide).

4.4.1. Géométrie simple

Une géométrie simple est une géométrie qui ne présente pas de points géométriques anormaux, tels qu'une intersection ou une tangence propre.

Un POINT est intrinsèquement simple en tant qu'objet géométrique à 0 dimension.

Les MULTIPOINT sont simples si deux coordonnées (POINTs) ne sont pas égales (ont des valeurs de coordonnées identiques).

Une LINESTRING est simple si elle ne passe pas deux fois par le même point, à l'exception des extrémités. Si les extrémités d'une simple LineString sont identiques, elle est dite fermée et appelée anneau linéaire.

(a) et (c) sont des LINESTRING simples. (b) et (d) ne sont pas simples. (c) est un anneau linéaire fermé.

(a)

(b)

(c)

(d)

Un MULTILINESTRING est simple uniquement si tous ses éléments sont simples et si la seule intersection entre deux éléments quelconques se produit en des points situés sur les limites des deux éléments.

(e) et (f) sont de simples MULTILINESTRINGs. (g) n'est pas simple.

(e)

(f)

(g)

Les POLYGON sont formés à partir d'anneaux linéaires, de sorte que la géométrie polygonale valide est toujours simple.

Pour tester si une géométrie est simple, utilisez la fonction ST_IsSimple :

SELECT
   ST_IsSimple('LINESTRING(0 0, 100 100)') AS straight,
   ST_IsSimple('LINESTRING(0 0, 100 100, 100 0, 0 100)') AS crossing;

 straight | crossing
----------+----------
 t        | f

En général, les fonctions PostGIS n'exigent pas que les arguments géométriques soient simples. La simplicité est principalement utilisée comme base pour définir la validité géométrique. C'est également une exigence pour certains types de modèles de données spatiales (par exemple, les réseaux linéaires interdisent souvent les lignes qui se croisent). La géométrie multipoint et linéaire peut être rendue simple en utilisant ST_UnaryUnion.

4.4.2. Géométrie valide

La validité géométrique s'applique principalement aux géométries bidimensionnelles (POLYGONs et MULTIPOLYGONs). La validité est définie par des règles qui permettent à la géométrie polygonale de modéliser des zones planes sans ambiguïté.

Un POLYGON est valide si :

  1. les anneaux de délimitation du polygone (l'anneau extérieur de la coquille et les anneaux intérieurs des trous) sont simples (ils ne se croisent pas et ne se touchent pas). Pour cette raison, un polygone ne peut pas avoir de lignes de coupe, de pointes ou de boucles. Cela implique que les trous des polygones doivent être représentés par des anneaux intérieurs, plutôt que par l'anneau extérieur qui se touche (ce qu'on appelle un "trou inversé").

  2. les anneaux de délimitation ne se croisent pas

  3. Les anneaux de délimitation peuvent se toucher en certains points, mais uniquement sous la forme d'une tangente (c'est-à-dire pas sous la forme d'une ligne).

  4. les anneaux intérieurs sont contenus dans l'anneau extérieur

  5. l'intérieur du polygone est simplement connecté (c'est-à-dire que les anneaux ne doivent pas se toucher d'une manière qui divise le polygone en plus d'une partie)

(h) et (i) sont des POLYGON valides. (j-m) ne sont pas valides. (j) peut être représenté comme un MULTIPOLYGON valide.

(h)

(i)

(j)

(k)

(l)

(m)

Un MULTIPOLYGON est valide si :

  1. ses éléments POLYGON sont valides

  2. les éléments ne se chevauchent pas (c'est-à-dire que leurs intérieurs ne doivent pas se croiser)

  3. les éléments ne se touchent que par des points (c'est-à-dire pas le long d'une ligne)

(n) est un MULTIPOLYGON valide. (o) et (p) ne sont pas valides.

(n)

(o)

(p)

Ces règles signifient que la géométrie polygonale valide est également simple.

Pour la géométrie linéaire, la seule règle de validité est que les LINESTRING doivent avoir au moins deux points et une longueur non nulle (ou, de façon équivalente, au moins deux points distincts).

SELECT
   ST_IsValid('LINESTRING(0 0, 1 1)') AS len_nonzero,
   ST_IsValid('LINESTRING(0 0, 0 0, 0 0)') AS len_zero,
   ST_IsValid('LINESTRING(10 10, 150 150, 180 50, 20 130)') AS self_int;

 len_nonzero | len_zero | self_int
-------------+----------+----------
 t           | f        | t

Les géométries POINT et MULTIPOINT n'ont pas de règles de validité.

4.4.3. Gestion de la validité

PostGIS permet de créer et de stocker des géométries valides et non valides. Cela permet de détecter les géométries non valides et de les signaler ou de les corriger. Il existe également des situations où les règles de validité de l'OGC sont plus strictes que souhaité (par exemple, les lignes de longueur nulle et les polygones avec des trous inversés).

De nombreuses fonctions fournies par PostGIS reposent sur l'hypothèse que les arguments géométriques sont valides. Par exemple, il n'est pas logique de calculer la surface d'un polygone dont le trou est défini à l'extérieur du polygone, ou de construire un polygone à partir d'une ligne de démarcation non simple. Le fait de supposer que les entrées géométriques sont valides permet aux fonctions de fonctionner plus efficacement, puisqu'elles n'ont pas besoin de vérifier l'exactitude topologique. (Les exceptions notables sont que les lignes de longueur nulle et les polygones avec des inversions sont généralement traités correctement). En outre, la plupart des fonctions PostGIS produisent une géométrie valide si les données d'entrée sont valides. Cela permet d'enchaîner les fonctions PostGIS en toute sécurité.

Si vous rencontrez des messages d'erreur inattendus lors de l'appel de fonctions PostGIS (tels que "GEOS Intersection() threw an error !"), vous devez d'abord vous assurer que les arguments de la fonction sont valides. Si ce n'est pas le cas, envisagez d'utiliser l'une des techniques ci-dessous pour vous assurer que les données que vous traitez sont valides.

[Note]

Si une fonction signale une erreur avec des entrées valides, il se peut que vous ayez trouvé une erreur dans PostGIS ou dans l'une des bibliothèques qu'il utilise, et vous devez le signaler au projet PostGIS. Il en va de même si une fonction PostGIS renvoie une géométrie non valide pour des données d'entrée valides.

Pour vérifier si une géométrie est valide, utilisez la fonction ST_IsValid :

SELECT ST_IsValid('POLYGON ((20 180, 180 180, 180 20, 20 20, 20 180))');
-----------------
 t

Les informations relatives à la nature et à la localisation d'une invalidité géométrique sont fournies par la fonction ST_IsValidDetail :

SELECT valid, reason, ST_AsText(location) AS location
    FROM ST_IsValidDetail('POLYGON ((20 20, 120 190, 50 190, 170 50, 20 20))') AS t;

 valid |      reason       |                  location
-------+-------------------+---------------------------------------------
 f     | Self-intersection | POINT(91.51162790697674 141.56976744186045)

Dans certaines situations, il est souhaitable de corriger automatiquement la géométrie non valide. Utilisez la fonction ST_MakeValid pour ce faire. (ST_MakeValid est un exemple de fonction spatiale qui doit permettre une entrée non valide).

Par défaut, PostGIS ne vérifie pas la validité lors du chargement de la géométrie, car les tests de validité peuvent prendre beaucoup de temps CPU pour les géométries complexes. Si vous ne faites pas confiance à vos sources de données, vous pouvez imposer un contrôle de validité à vos tables en ajoutant une contrainte de contrôle :

ALTER TABLE mytable
  ADD CONSTRAINT geometry_valid_check
        CHECK (ST_IsValid(geom));

4.5. Systèmes de référence spatiale

Un système de référence spatiale (SRS) (également appelé système de référence des coordonnées (SRC)) définit la manière dont la géométrie est référencée par rapport à des emplacements sur la surface de la Terre. Il existe trois types de SRS :

  • Un SRS géodésique utilise des coordonnées angulaires (longitude et latitude) qui correspondent directement à la surface de la terre.

  • Un SRS projeté utilise une transformation mathématique de projection pour "aplatir" la surface de la terre sphéroïdale sur un plan. Il attribue des coordonnées de localisation d'une manière qui permet de mesurer directement des quantités telles que la distance, la surface et l'angle. Le système de coordonnées est cartésien, ce qui signifie qu'il a un point d'origine défini et deux axes perpendiculaires (généralement orientés vers le nord et l'est). Chaque SRS projeté utilise une unité de longueur définie (généralement des mètres ou des pieds). Un SRS projeté peut être limité dans sa zone d'applicabilité afin d'éviter toute distorsion et de s'inscrire dans les limites des coordonnées définies.

  • Un SRS local est un système de coordonnées cartésiennes qui n'est pas référencé à la surface de la terre. Dans PostGIS, ce système est spécifié par une valeur SRID de 0.

Il existe de nombreux systèmes de référence spatiale différents. Les SRS courants sont normalisés dans la base de données de l'European Petroleum Survey Group EPSG database. Par commodité, PostGIS (et de nombreux autres systèmes spatiaux) se réfère aux définitions des SRS à l'aide d'un identifiant entier appelé SRID.

Une géométrie est associée à un système de référence spatiale par sa valeur SRID, à laquelle on accède par ST_SRID. Le SRID d'une géométrie peut être assigné en utilisant ST_SetSRID. Certaines fonctions de construction de géométrie permettent de fournir un SRID (telles que ST_Point et ST_MakeEnvelope). Le format EWKT prend en charge les SRID avec le préfixe SRID=n;.

Les fonctions spatiales qui traitent des paires de géométries (telles que les fonctions overlay et relationship) exigent que les géométries d'entrée soient dans le même système de référence spatiale (qu'elles aient le même SRID). Les données géométriques peuvent être transformées dans un système de référence spatiale différent en utilisant ST_Transform et ST_TransformPipeline. Les géométries renvoyées par les fonctions ont le même SRS que les géométries d'entrée.

4.5.1. Table SPATIAL_REF_SYS

La table SPATIAL_REF_SYS utilisée par PostGIS est une table de base de données conforme à l'OGC qui définit les systèmes de référence spatiale disponibles. Elle contient les SRID numériques et les descriptions textuelles des systèmes de coordonnées.

La définition de la table spatial_ref_sys est la suivante :

CREATE TABLE spatial_ref_sys (
  srid       INTEGER NOT NULL PRIMARY KEY,
  auth_name  VARCHAR(256),
  auth_srid  INTEGER,
  srtext     VARCHAR(2048),
  proj4text  VARCHAR(2048)
)

Les colonnes sont :

srid

Un code entier qui identifie de manière unique le Système de référence spatiale (SRS) dans la base de données.

auth_name

Le nom de la norme ou de l'organisme de normalisation qui est cité pour ce système de référence. Par exemple, "EPSG" est un auth_name valide.

auth_srid

L'ID du système de référence spatiale tel que défini par l'autorité citée dans le auth_name. Dans le cas de l'EPSG, il s'agit du code EPSG.

srtext

Représentation Well-Known Text du système de référence spatiale. Un exemple de représentation WKT du SRS est le suivant :

PROJCS["NAD83 / UTM Zone 10N",
  GEOGCS["NAD83",
        DATUM["North_American_Datum_1983",
          SPHEROID["GRS 1980",6378137,298.257222101]
        ],
        PRIMEM["Greenwich",0],
        UNIT["degree",0.0174532925199433]
  ],
  PROJECTION["Transverse_Mercator"],
  PARAMETER["latitude_of_origin",0],
  PARAMETER["central_meridian",-123],
  PARAMETER["scale_factor",0.9996],
  PARAMETER["false_easting",500000],
  PARAMETER["false_northing",0],
  UNIT["metre",1]
]

Pour une discussion sur le SRS WKT, voir la norme OGC Well-known text representation of coordinate reference systems.

proj4text

PostGIS utilise la bibliothèque PROJ pour fournir des capacités de transformation de coordonnées. La colonne proj4text contient la chaîne de caractères de définition des coordonnées PROJ pour un SRID particulier. Par exemple :

+proj=utm +zone=10 +ellps=clrk66 +datum=NAD27 +units=m

Pour plus d'informations, consultez le site web de PROJ. Le fichier spatial_ref_sys.sql contient les définitions srtext et proj4text pour toutes les projections EPSG.

Lors de la récupération des définitions des systèmes de référence spatiale pour les utiliser dans les transformations, PostGIS utilise la stratégie suivante :

  • Si auth_name et auth_srid sont présents (non NULL), utiliser le PROJ SRS basé sur ces entrées (si au moins un existe).

  • Si srtext est présent, créez un SRS en l'utilisant, si possible.

  • Si proj4text est présent, créez un SRS en l'utilisant, si possible.

4.5.2. Systèmes de référence spatiale définis par l'utilisateur

La table PostGIS spatial_ref_sys contient plus de 3000 définitions des systèmes de référence spatiale les plus courants qui sont gérés par la bibliothèque de projection PROJ. Mais il existe de nombreux systèmes de coordonnées qu'elle ne contient pas. Vous pouvez ajouter des définitions de SRS à la table si vous disposez des informations requises sur le système de référence spatiale. Vous pouvez également définir votre propre système de référence spatiale personnalisé si vous êtes familiarisé avec les constructions PROJ. Gardez à l'esprit que la plupart des systèmes de référence spatiale sont régionaux et n'ont aucune signification lorsqu'ils sont utilisés en dehors des limites pour lesquelles ils ont été conçus.

Une ressource permettant de trouver des systèmes de référence spatiale non définis dans le jeu de base est http://spatialreference.org/

Les systèmes de référence spatiale les plus couramment utilisés sont les suivants : 4326 - WGS 84 Long Lat, 4269 - NAD 83 Long Lat, 3395 - WGS 84 World Mercator, 2163 - US National Atlas Equal Area, et les 60 zones UTM WGS84. Les zones UTM sont parmi les plus idéales pour les mesures, mais elles ne couvrent que des régions de 6 degrés. (Pour déterminer la zone UTM à utiliser pour votre zone d'intérêt, voir la utmzone PostGIS plpgsql helper function.)

Les États américains utilisent des systèmes de référence spatiale State Plane (basés sur le mètre ou le pied) - il en existe généralement un ou deux par État. La plupart des systèmes basés sur le mètre se trouvent dans le jeu de base, mais de nombreux systèmes basés sur le pied ou créés par ESRI devront être copiés à partir de spatialreference.org.

Vous pouvez même définir des systèmes de coordonnées non terrestres, tels que Mars 2000 Ce système de coordonnées martien n'est pas planaire (il est en degrés sphéroïdaux), mais vous pouvez l'utiliser avec le type géographie pour obtenir des mesures de longueur et de proximité en mètres au lieu de degrés.

Voici un exemple de chargement d'un système de coordonnées personnalisé à l'aide d'un SRID non attribué et de la définition PROJ pour une projection Lambert conforme centrée sur les États-Unis :

INSERT INTO spatial_ref_sys (srid, proj4text)
VALUES ( 990000,
  '+proj=lcc  +lon_0=-95 +lat_0=25 +lat_1=25 +lat_2=25 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs'
);

4.6. Tables spatiales

4.6.1. Créer une table spatiale

Vous pouvez créer une table pour stocker des données géométriques en utilisant l'instruction SQL CREATE TABLE avec une colonne de type geometry. L'exemple suivant crée une table avec une colonne géométrie stockant des chaînes de lignes 2D (XY) dans le système de coordonnées BC-Albers (SRID 3005) :

CREATE TABLE roads (
    id SERIAL PRIMARY KEY,
    name VARCHAR(64),
    geom geometry(LINESTRING,3005)
  );

Le type geometry prend en charge deux modificateurs de type facultatifs :

  • le modificateur de type spatial restreint le type de formes et de dimensions autorisées dans la colonne. La valeur peut être l'un des sous-types de géométrie pris en charge (par exemple POINT, LINESTRING, POLYGON, MULTIPOINT, MULTILINESTRING, MULTIPOLYGON, GEOMETRYCOLLECTION, etc). Le modificateur prend en charge les restrictions de dimensionnalité des coordonnées en ajoutant des suffixes : Z, M et ZM. Par exemple, le modificateur "LINESTRINGM" n'autorise que les lignes à trois dimensions et traite la troisième dimension comme une mesure. De même, "POINTZM" requiert des données à quatre dimensions (XYZM).

  • le modificateur SRID limite le système de référence spatiale SRID à un nombre particulier. S'il est omis, le SRID prend par défaut la valeur 0.

Exemples de création de tableaux avec des colonnes géométriques :

  • Créer une table contenant n'importe quel type de géométrie avec le SRID par défaut :

    CREATE TABLE geoms(gid serial PRIMARY KEY, geom geometry );
  • Créer une table avec une géométrie POINT 2D avec le SRID par défaut :

    CREATE TABLE pts(gid serial PRIMARY KEY, geom geometry(POINT) );
  • Créer une table avec des POINTS 3D (XYZ) et un SRID explicite de 3005 :

    CREATE TABLE pts(gid serial PRIMARY KEY, geom geometry(POINTZ,3005) );
  • Créer une table avec une géométrie 4D (XYZM) LINESTRING avec le SRID par défaut :

    CREATE TABLE lines(gid serial PRIMARY KEY, geom geometry(LINESTRINGZM) );
  • Créer une table avec une géométrie POLYGON 2D avec le SRID 4267 (NAD 1927 long lat) :

    CREATE TABLE polys(gid serial PRIMARY KEY, geom geometry(POLYGON,4267) );

Il est possible d'avoir plus d'une colonne de géométrie dans une table. Cela peut être spécifié lors de la création de la table, ou une colonne peut être ajoutée à l'aide de l'instruction SQL ALTER TABLE. Cet exemple ajoute une colonne qui peut contenir des LineStrings 3D :

ALTER TABLE roads ADD COLUMN geom2 geometry(LINESTRINGZ,4326);

4.6.2. Vue GEOMETRY_COLUMNS

L'OGC Simple Features Specification for SQL définit la table de métadonnées GEOMETRY_COLUMNS pour décrire la structure de la table géométrique. Dans PostGIS, geometry_columns est une vue qui lit les tables de catalogue du système de base de données. Cela garantit que les informations de métadonnées spatiales sont toujours cohérentes avec les tables et les vues actuellement définies. La structure de la vue est la suivante :

\d geometry_columns
View "public.geometry_columns"
      Column       |          Type          | Modifiers
-------------------+------------------------+-----------
 f_table_catalog   | character varying(256) |
 f_table_schema    | character varying(256) |
 f_table_name      | character varying(256) |
 f_geometry_column | character varying(256) |
 coord_dimension   | integer                |
 srid              | integer                |
 type              | character varying(30)  |

Les colonnes sont :

f_table_catalog, f_table_schema, f_table_name

Le nom complet de la table d'entités contenant la colonne géométrie. Il n'y a pas d'analogue PostgreSQL de "catalog", cette colonne est donc laissée vide. Pour "schema", le nom du schéma PostgreSQL est utilisé (public est la valeur par défaut).

f_geometry_column

Le nom de la colonne géométrique dans la table des caractéristiques.

coord_dimension

La dimension des coordonnées (2, 3 ou 4) de la colonne.

srid

L'ID du système de référence spatiale utilisé pour la géométrie des coordonnées dans cette table. Il s'agit d'une référence de clé étrangère à la table spatial_ref_sys (voir Section 4.5.1, “Table SPATIAL_REF_SYS”).

type

Le type de l'objet spatial. Pour limiter la colonne spatiale à un seul type, utilisez l'une des options suivantes : POINT, LINESTRING, POLYGON, MULTIPOINT, MULTILINESTRING, MULTIPOLYGON, GEOMETRYCOLLECTION ou les versions XYM correspondantes POINTM, LINESTRINGM, POLYGONM, MULTIPOINTM, MULTILINESTRINGM, MULTIPOLYGONM, GEOMETRYCOLLECTIONM. Pour les collections hétérogènes (de type mixte), vous pouvez utiliser "GEOMETRY" comme type.

4.6.3. Enregistrement manuel des colonnes de géométrie

Deux des cas où vous pouvez avoir besoin de cela sont les cas de vues SQL et les insertions en masse. Dans le cas des insertions en masse, vous pouvez corriger l'enregistrement dans la table geometry_columns en contraignant la colonne ou en effectuant une modification de la table. Pour les vues, vous pouvez exposer en utilisant une opération CAST. Notez que si votre colonne est basée sur un typmod, le processus de création l'enregistrera correctement, il n'est donc pas nécessaire de faire quoi que ce soit. De même, les vues qui n'ont pas de fonction spatiale appliquée à la géométrie s'enregistreront de la même manière que la colonne géométrique de la table sous-jacente.

-- Lets say you have a view created like this
CREATE VIEW public.vwmytablemercator AS
        SELECT gid, ST_Transform(geom, 3395) As geom, f_name
        FROM public.mytable;

-- For it to register correctly
-- You need to cast the geometry
--
DROP VIEW public.vwmytablemercator;
CREATE VIEW  public.vwmytablemercator AS
        SELECT gid, ST_Transform(geom, 3395)::geometry(Geometry, 3395) As geom, f_name
        FROM public.mytable;

-- If you know the geometry type for sure is a 2D POLYGON then you could do
DROP VIEW public.vwmytablemercator;
CREATE VIEW  public.vwmytablemercator AS
        SELECT gid, ST_Transform(geom,3395)::geometry(Polygon, 3395) As geom, f_name
        FROM public.mytable;
--Lets say you created a derivative table by doing a bulk insert
SELECT poi.gid, poi.geom, citybounds.city_name
INTO myschema.my_special_pois
FROM poi INNER JOIN citybounds ON ST_Intersects(citybounds.geom, poi.geom);

-- Create 2D index on new table
CREATE INDEX idx_myschema_myspecialpois_geom_gist
  ON myschema.my_special_pois USING gist(geom);

-- If your points are 3D points or 3M points,
-- then you might want to create an nd index instead of a 2D index
CREATE INDEX my_special_pois_geom_gist_nd
        ON my_special_pois USING gist(geom gist_geometry_ops_nd);

-- To manually register this new table's geometry column in geometry_columns.
-- Note it will also change the underlying structure of the table to
-- to make the column typmod based.
SELECT populate_geometry_columns('myschema.my_special_pois'::regclass);

-- If you are using PostGIS 2.0 and for whatever reason, you
-- you need the constraint based definition behavior
-- (such as case of inherited tables where all children do not have the same type and srid)
-- set optional use_typmod argument to false
SELECT populate_geometry_columns('myschema.my_special_pois'::regclass, false); 

Bien que l'ancienne méthode basée sur les contraintes soit toujours supportée, une colonne géométrique basée sur les contraintes utilisée directement dans une vue ne s'enregistrera pas correctement dans geometry_columns, tout comme une colonne typmod. Dans cet exemple, nous définissons une colonne à l'aide de typmod et une autre à l'aide de contraintes.

CREATE TABLE pois_ny(gid SERIAL PRIMARY KEY, poi_name text, cat text, geom geometry(POINT,4326));
SELECT AddGeometryColumn('pois_ny', 'geom_2160', 2160, 'POINT', 2, false);

Si nous exécutons dans psql

\d pois_ny;

Nous observons qu'ils sont définis différemment - l'un est un typmod, l'autre une contrainte

Table "public.pois_ny"
  Column   |         Type          |                       Modifiers

-----------+-----------------------+------------------------------------------------------
 gid       | integer               | not null default nextval('pois_ny_gid_seq'::regclass)
 poi_name  | text                  |
 cat       | character varying(20) |
 geom      | geometry(Point,4326)  |
 geom_2160 | geometry              |
Indexes:
    "pois_ny_pkey" PRIMARY KEY, btree (gid)
Check constraints:
    "enforce_dims_geom_2160" CHECK (st_ndims(geom_2160) = 2)
    "enforce_geotype_geom_2160" CHECK (geometrytype(geom_2160) = 'POINT'::text
        OR geom_2160 IS NULL)
    "enforce_srid_geom_2160" CHECK (st_srid(geom_2160) = 2160)

Dans geometry_columns, les deux s'enregistrent correctement

SELECT f_table_name, f_geometry_column, srid, type
        FROM geometry_columns
        WHERE f_table_name = 'pois_ny';
f_table_name | f_geometry_column | srid | type
-------------+-------------------+------+-------
pois_ny      | geom              | 4326 | POINT
pois_ny      | geom_2160         | 2160 | POINT

Cependant, si nous devions créer une vue comme celle-ci

CREATE VIEW vw_pois_ny_parks AS
SELECT *
  FROM pois_ny
  WHERE cat='park';

SELECT f_table_name, f_geometry_column, srid, type
        FROM geometry_columns
        WHERE f_table_name = 'vw_pois_ny_parks';

La colonne de la vue géométrique basée sur le modèle s'enregistre correctement, mais pas celle basée sur les contraintes.

f_table_name   | f_geometry_column | srid |   type
------------------+-------------------+------+----------
 vw_pois_ny_parks | geom              | 4326 | POINT
 vw_pois_ny_parks | geom_2160         |    0 | GEOMETRY

Cela pourrait changer dans les prochaines versions de PostGIS, mais pour l'instant, pour forcer la colonne de vue basée sur les contraintes à s'enregistrer correctement, vous devez procéder comme suit :

DROP VIEW vw_pois_ny_parks;
CREATE VIEW vw_pois_ny_parks AS
SELECT gid, poi_name, cat,
  geom,
  geom_2160::geometry(POINT,2160) As geom_2160
  FROM pois_ny
  WHERE cat = 'park';
SELECT f_table_name, f_geometry_column, srid, type
        FROM geometry_columns
        WHERE f_table_name = 'vw_pois_ny_parks';
f_table_name   | f_geometry_column | srid | type
------------------+-------------------+------+-------
 vw_pois_ny_parks | geom              | 4326 | POINT
 vw_pois_ny_parks | geom_2160         | 2160 | POINT

4.7. Chargement des données spatiales

Une fois que vous avez créé une table spatiale, vous êtes prêt à charger des données spatiales dans la base de données. Il existe deux façons d'intégrer des données spatiales dans une base de données PostGIS/PostgreSQL : à l'aide d'instructions SQL formatées ou à l'aide de l'utilitaire qui permet de charger des Shapefiles.

4.7.1. Utilisation de SQL pour charger des données

Si les données spatiales peuvent être converties en une représentation textuelle (WKT ou WKB), l'utilisation de SQL pourrait être le moyen le plus simple d'introduire les données dans PostGIS. Les données peuvent être chargées en masse dans PostGIS/PostgreSQL en chargeant un fichier texte d'instructions SQL INSERT à l'aide de l'utilitaire SQL psql.

Un fichier de chargement SQL (roads.sql par exemple) peut ressembler à ceci :

BEGIN;
INSERT INTO roads (road_id, roads_geom, road_name)
  VALUES (1,'LINESTRING(191232 243118,191108 243242)','Jeff Rd');
INSERT INTO roads (road_id, roads_geom, road_name)
  VALUES (2,'LINESTRING(189141 244158,189265 244817)','Geordie Rd');
INSERT INTO roads (road_id, roads_geom, road_name)
  VALUES (3,'LINESTRING(192783 228138,192612 229814)','Paul St');
INSERT INTO roads (road_id, roads_geom, road_name)
  VALUES (4,'LINESTRING(189412 252431,189631 259122)','Graeme Ave');
INSERT INTO roads (road_id, roads_geom, road_name)
  VALUES (5,'LINESTRING(190131 224148,190871 228134)','Phil Tce');
INSERT INTO roads (road_id, roads_geom, road_name)
  VALUES (6,'LINESTRING(198231 263418,198213 268322)','Dave Cres');
COMMIT;

Le fichier SQL peut être chargé dans PostgreSQL en utilisant psql :

psql -d [database] -f roads.sql

4.7.2. Utilisation de l'utilitaire qui permet de charger des fichiers Shapefile

Le chargeur de données shp2pgsql convertit les Shapefiles en SQL pour les insérer dans une base de données PostGIS/PostgreSQL au format geometry ou geography. Le chargeur a plusieurs modes de fonctionnement sélectionnés par des indicateurs de ligne de commande.

Il existe également une interface graphique shp2pgsql-gui qui offre la plupart des options du chargeur en ligne de commande. Cette interface peut être plus facile à utiliser pour un chargement ponctuel sans script ou si vous êtes novice en matière de PostGIS. Il peut également être configuré comme un plugin pour PgAdminIII.

(c|a|d|p) Ces options s'excluent mutuellement :

-c

Crée une nouvelle table et la remplit à partir du fichier Shapefile. C'est le mode par défaut.

-a

Ajoute les données du fichier Shapefile dans la table de la base de données. Notez que pour utiliser cette option afin de charger plusieurs fichiers, les fichiers doivent avoir les mêmes attributs et les mêmes types de données.

-d

Supprime la table de la base de données avant de créer une nouvelle table avec les données du fichier Shapefile.

-p

Produit uniquement le code SQL de création de la table, sans ajouter de données réelles. Cette option peut être utilisée si vous souhaitez séparer complètement les étapes de création de la table et de chargement des données.

-?

Afficher l'écran d'aide.

-D

Utilise le format "dump" de PostgreSQL pour les données de sortie. Ce format peut être combiné avec -a, -c et -d. Il est beaucoup plus rapide à charger que le format SQL "insert" par défaut. Utilisez-le pour les très grands ensembles de données.

-s [<FROM_SRID>:]<SRID>

Crée et remplit les tables de géométrie avec le SRID spécifié. Il est possible de spécifier que le fichier de forme d'entrée utilise le FROM_SRID donné, auquel cas les géométries seront reprojetées dans le SRID cible.

-k

Conserver la casse des identifiants (colonne, schéma et attributs). Notez que les attributs dans Shapefile sont tous en majuscules.

-i

Contraindre tous les entiers à des entiers 32 bits standard, ne pas créer de bigints 64 bits, même si la signature de l'en-tête DBF semble le justifier.

-I

Créer un index GiST sur la colonne géométrie.

-m

-m nom_de_fichier Spécifier un fichier contenant un ensemble de correspondances entre les noms de colonnes (longs) et les noms de colonnes DBF à 10 caractères. Le contenu du fichier est une ou plusieurs lignes de deux noms séparées par un espace blanc, sans espace de départ ni de fin. Par exemple :

COLUMNNAME DBFFIELD1
AVERYLONGCOLUMNNAME DBFFIELD2

-S

Génère des géométries simples au lieu de géométries MULTI. Ne réussira que si toutes les géométries sont en fait simples (c'est-à-dire un MULTIPOLYGON avec une seule enveloppe, ou un MULTIPOINT avec un seul sommet).

-t <dimensionality>

Force la géométrie de sortie à avoir la dimensionnalité spécifiée. Utilisez les chaînes de caractères suivantes pour indiquer la dimensionnalité : 2D, 3DZ, 3DM, 4D.

Si l'entrée a moins de dimensions que celles spécifiées, la sortie aura ces dimensions remplies avec des zéros. Si l'entrée a plus de dimensions que celles spécifiées, les dimensions non désirées seront supprimées.

-w

Sortie au format WKT, au lieu de WKB. Notez que cela peut introduire des dérives de coordonnées dues à la perte de précision.

-e

Exécuter chaque instruction séparément, sans utiliser de transaction. Cela permet de charger la majorité des bonnes données lorsqu'il y a quelques mauvaises géométries qui génèrent des erreurs. Notez que cela ne peut pas être utilisé avec l'option -D car le format "dump" utilise toujours une transaction.

-W <encoding>

Spécifie l'encodage des données d'entrée (fichier dbf). Lorsqu'il est utilisé, tous les attributs du fichier dbf sont convertis en UTF8 à partir de l'encodage spécifié. La sortie SQL résultante contiendra une commande SET CLIENT_ENCODING to UTF8, afin que le backend puisse reconvertir de UTF8 à n'importe quel encodage que la base de données est configurée pour utiliser en interne.

-N <policy>

Politique de gestion des géométries NULL (insert*, skip, abort)

-n

-n Importer uniquement le fichier DBF. Si vos données n'ont pas de fichier de forme correspondant, il passera automatiquement à ce mode et ne chargera que le fichier DBF. Cette option n'est donc nécessaire que si vous disposez d'un fichier de forme complet et que vous ne voulez que les données d'attributs et pas de géométrie.

-G

Utiliser le type geography au lieu de geometry (nécessite des données lon/lat) dans WGS84 long lat (SRID=4326)

-T <tablespace>

Spécifiez le tablespace pour la nouvelle table. Les index utiliseront toujours le tablespace par défaut à moins que le paramètre -X ne soit également utilisé. La documentation de PostgreSQL contient une bonne description de l'utilisation des tablespaces personnalisés.

-X <tablespace>

Spécifier le tablespace pour les index de la nouvelle table. Ceci s'applique à l'index de clé primaire et à l'index spatial GIST si -I est également utilisé.

-Z

Lorsqu'il est utilisé, cet indicateur empêche la génération des instructions ANALYZE. Sans l'option -Z (comportement par défaut), les instructions ANALYZE seront générées.

Un exemple de session utilisant le chargeur pour créer un fichier d'entrée et le charger peut ressembler à ceci :

# shp2pgsql -c -D -s 4269 -i -I shaperoads.shp myschema.roadstable > roads.sql
# psql -d roadsdb -f roads.sql

Une conversion et un chargement peuvent être effectués en une seule étape à l'aide de pipes UNIX :

# shp2pgsql shaperoads.shp myschema.roadstable | psql -d roadsdb

4.8. Extraction de données spatiales

Les données spatiales peuvent être extraites de la base de données à l'aide de SQL ou de Shapefile dumper. La section sur SQL présente certaines des fonctions disponibles pour effectuer des comparaisons et des requêtes sur les tables spatiales.

4.8.1. Utiliser SQL pour extraire des données

La manière la plus simple d'extraire des données spatiales de la base de données consiste à utiliser une requête SQL SELECT pour définir l'ensemble de données à extraire et à transférer les colonnes résultantes dans un fichier texte analysable :

db=# SELECT road_id, ST_AsText(road_geom) AS geom, road_name FROM roads;

road_id | geom                                    | road_name
--------+-----------------------------------------+-----------
          1 | LINESTRING(191232 243118,191108 243242) | Jeff Rd
          2 | LINESTRING(189141 244158,189265 244817) | Geordie Rd
          3 | LINESTRING(192783 228138,192612 229814) | Paul St
          4 | LINESTRING(189412 252431,189631 259122) | Graeme Ave
          5 | LINESTRING(190131 224148,190871 228134) | Phil Tce
          6 | LINESTRING(198231 263418,198213 268322) | Dave Cres
          7 | LINESTRING(218421 284121,224123 241231) | Chris Way
(6 rows)

Il peut arriver qu'une restriction soit nécessaire pour réduire le nombre d'enregistrements renvoyés. Dans le cas de restrictions basées sur des attributs, utilisez la même syntaxe SQL que pour une table non spatiale. Dans le cas de restrictions spatiales, les fonctions suivantes sont utiles :

ST_Intersects

Cette fonction indique si deux géométries partagent un espace.

=

Cette fonction permet de vérifier si deux géométries sont géométriquement identiques. Par exemple, si 'POLYGON((0 0,1 1,1 0,0 0))' est identique à 'POLYGON((0 0,1 1,1 0,0 0))' (c'est le cas).

Vous pouvez ensuite utiliser ces opérateurs dans des requêtes. Notez que lorsque vous spécifiez des géométries et des box sur la ligne de commande SQL, vous devez explicitement transformer les représentations de chaînes de caractères en fonction géométrique. Le 312 est un système de référence spatiale fictif qui correspond à nos données. Ainsi, par exemple, le 312 est un système de référence spatiale fictif qui correspond à nos données :

SELECT road_id, road_name
  FROM roads
  WHERE roads_geom='SRID=312;LINESTRING(191232 243118,191108 243242)'::geometry;

La requête ci-dessus renverrait le seul enregistrement de la table "ROADS_GEOM" dont la géométrie est égale à cette valeur.

Vérifier si certaines routes passent dans la zone définie par un polygone :

SELECT road_id, road_name
FROM roads
WHERE ST_Intersects(roads_geom, 'SRID=312;POLYGON((...))');

La requête spatiale la plus courante sera probablement une requête "basée sur un cadre", utilisée par les logiciels clients, tels que les navigateurs de données et les cartographes web, pour saisir un "cadre de carte" d'une valeur de données pour l'affichage.

Lorsque vous utilisez l'opérateur "&&", vous pouvez spécifier soit une BOX3D comme élément de comparaison, soit une GEOMETRY. Toutefois, lorsque vous spécifiez une GEOMETRY, c'est sa boîte de délimitation qui sera utilisée pour la comparaison.

En utilisant un objet "BOX3D" pour le cadre, une telle requête se présente comme suit :

SELECT ST_AsText(roads_geom) AS geom
FROM roads
WHERE
  roads_geom && ST_MakeEnvelope(191232, 243117,191232, 243119,312);

Notez l'utilisation du SRID 312 pour spécifier la projection de l'enveloppe.

4.8.2. Utilisation de Shapefile Dumper

Le table dumper pgsql2shp se connecte à la base de données et convertit une table (éventuellement définie par une requête) en un fichier shape. La syntaxe de base est la suivante :

pgsql2shp [<options>] <database> [<schema>.]<table>
pgsql2shp [<options>] <database> <query>

Les options de la ligne de commande sont les suivantes :

-f <filename>

Écriture de la sortie dans un fichier particulier.

-h <host>

L'hôte de la base de données auquel se connecter.

-p <port>

Le port auquel se connecter sur l'hôte de la base de données.

-P <password>

Le mot de passe à utiliser lors de la connexion à la base de données.

-u <user>

Le nom d'utilisateur à utiliser lors de la connexion à la base de données.

-g <geometry column>

Dans le cas de tableaux comportant plusieurs colonnes géométriques, la colonne géométrique à utiliser lors de l'écriture du fichier de forme.

-b

Utiliser un curseur binaire. L'opération sera plus rapide, mais ne fonctionnera pas si un attribut NON-geometry de la table n'est pas converti en texte.

-r

Mode brut. Ne pas supprimer le champ gid, ni échapper les noms de colonnes.

-m filename

Remapper les identifiants en noms de dix caractères. Le contenu du fichier est constitué de lignes de deux symboles séparées par un seul espace blanc, sans espace de départ ni de fin : VERYLONGSYMBOL SHORTONE ANOTHERYLONGSYMBOL SHORTER etc.

4.9. Index spatiaux

Les index spatiaux permettent d'utiliser une base de données spatiales pour de grands ensembles de données. Sans indexation, la recherche de caractéristiques nécessite un balayage séquentiel de chaque enregistrement de la base de données. L'indexation accélère la recherche en organisant les données dans une structure qui peut être rapidement parcourue pour trouver les enregistrements correspondants.

La méthode d'indexation B-tree couramment utilisée pour les données d'attributs n'est pas très utile pour les données spatiales, car elle ne permet de stocker et d'interroger les données que dans une seule dimension. Les données telles que la géométrie (qui a 2 dimensions ou plus) requièrent une méthode d'indexation qui supporte les requêtes sur toutes les dimensions des données. L'un des principaux avantages de PostgreSQL pour le traitement des données spatiales est qu'il offre plusieurs types de méthodes d'indexation qui fonctionnent bien pour les données multidimensionnelles : GiST, BRIN et SP-GiST.

  • Les index GiST (Generalized Search Tree) décomposent les données en "choses à côté", "choses qui se chevauchent", "choses qui sont à l'intérieur" et peuvent être utilisés sur un large éventail de types de données, y compris les données SIG. PostGIS utilise un index R-Tree implémenté au-dessus de GiST pour indexer les données spatiales. GiST est la méthode d'indexation spatiale la plus couramment utilisée et la plus polyvalente, et offre de très bonnes performances en matière de requêtes.

  • Les index BRIN (Block Range Index) fonctionnent en résumant l'étendue spatiale des plages d'enregistrements de la table. La recherche s'effectue par le biais d'un balayage des plages. L'index BRIN n'est approprié que pour certains types de données (triées dans l'espace, avec des mises à jour peu fréquentes ou inexistantes). Mais il permet une création d'index beaucoup plus rapide et une taille d'index beaucoup plus petite.

  • SP-GiST (Space-Partitioned Generalized Search Tree) est une méthode d'indexation générique qui prend en charge les arbres de recherche partitionnés tels que les arbres quadratiques, les arbres k-d et les arbres radix (tries).

Les index spatiaux ne stockent que la boîte de délimitation des géométries. Les requêtes spatiales utilisent l'index comme filtre primaire pour déterminer rapidement un ensemble de géométries correspondant potentiellement à la condition de la requête. La plupart des requêtes spatiales nécessitent un filtre secondaire qui utilise une fonction de prédicat spatial pour tester une condition spatiale plus spécifique. Pour plus d'informations sur les requêtes avec des prédicats spatiaux, voir Section 5.2, “Utilisation des index spatiaux”.

Voir également la section de l'atelier PostGIS sur les index spatiaux et le manuel de PostgreSQL.

4.9.1. Index GiST

GiST signifie "Generalized Search Tree" (arbre de recherche généralisé) et constitue une forme générique d'indexation pour les données multidimensionnelles. PostGIS utilise un index R-Tree implémenté au-dessus de GiST pour indexer les données spatiales. GiST est la méthode d'indexation spatiale la plus couramment utilisée et la plus polyvalente, et offre de très bonnes performances en matière de requêtes. D'autres implémentations de GiST sont utilisées pour accélérer les recherches sur toutes sortes de structures de données irrégulières (tableaux d'entiers, données spectrales, etc.) qui ne se prêtent pas à l'indexation B-Tree normale. Pour plus d'informations, voir le manuel PostgreSQL.

Dès qu'une table de données spatiales dépasse quelques milliers de lignes, vous devez créer un index pour accélérer les recherches spatiales dans les données (sauf si toutes vos recherches sont basées sur des attributs, auquel cas vous devez créer un index normal sur les champs d'attributs).

La syntaxe pour construire un index GiST sur une colonne "geometry" est la suivante :

CREATE INDEX [indexname] ON [tablename] USING GIST ( [geometryfield] ); 

La syntaxe ci-dessus permet toujours de créer un index 2D. Pour obtenir un index à n dimensions pour le type de géométrie, vous pouvez en créer un à l'aide de cette syntaxe :

CREATE INDEX [indexname] ON [tablename] USING GIST ([geometryfield] gist_geometry_ops_nd);

La construction d'un index spatial est un exercice de calcul intensif. Il bloque également l'accès en écriture à votre table pendant le temps de sa création, donc sur un système de production, vous voudrez peut-être le faire d'une manière plus lente, en tenant compte de la notion de CONCURRENCE :

CREATE INDEX CONCURRENTLY [indexname] ON [tablename] USING GIST ( [geometryfield] ); 

Après avoir construit un index, il est parfois utile de forcer PostgreSQL à collecter les statistiques de la table, qui sont utilisées pour optimiser les plans de requête :

VACUUM ANALYZE [table_name] [(column_name)];

4.9.2. Index BRIN

BRIN signifie "Block Range Index". C'est une méthode d'indexation générale introduite dans PostgreSQL 9.5. BRIN est une méthode d'indexation lossy, ce qui signifie qu'une vérification secondaire est nécessaire pour confirmer qu'un enregistrement correspond à une condition de recherche donnée (ce qui est le cas pour tous les index spatiaux fournis). Elle permet une création d'index beaucoup plus rapide et une taille d'index beaucoup plus petite, avec des performances de lecture raisonnables. Son objectif principal est de permettre l'indexation de très grandes tables sur des colonnes qui ont une corrélation avec leur emplacement physique dans la table. Outre l'indexation spatiale, BRIN peut accélérer les recherches sur divers types de structures de données d'attributs (entiers, tableaux, etc.). Pour plus d'informations, voir le Manuel de PostgreSQL.

Dès qu'une table spatiale dépasse quelques milliers de lignes, vous voudrez construire un index pour accélérer les recherches spatiales dans les données. Les index GiST sont très performants tant que leur taille ne dépasse pas la quantité de mémoire vive disponible pour la base de données, et tant que vous pouvez vous permettre la taille de stockage de l'index et le coût de la mise à jour de l'index en écriture. Sinon, pour les très grandes tables, l'index BRIN peut être considéré comme une alternative.

Un index BRIN stocke la boîte englobant toutes les géométries contenues dans les lignes d'un ensemble contigu de blocs de table, appelé plage de blocs. Lors de l'exécution d'une requête à l'aide de l'index, les plages de blocs sont examinées pour trouver celles qui recoupent l'étendue de la requête. Cette méthode n'est efficace que si les données sont physiquement ordonnées de manière à ce que les zones de délimitation des plages de blocs se chevauchent le moins possible (et, dans l'idéal, s'excluent mutuellement). L'index qui en résulte est de très petite taille, mais il est généralement moins performant en lecture qu'un index GiST sur les mêmes données.

La construction d'un index BRIN est beaucoup moins gourmande en ressources CPU que la construction d'un index GiST. Il est courant de constater qu'un index BRIN est dix fois plus rapide à construire qu'un index GiST pour les mêmes données. Et comme un index BRIN ne stocke qu'une seule boîte englobante pour chaque plage de blocs de table, il est courant d'utiliser jusqu'à mille fois moins d'espace disque qu'un index GiST.

Vous pouvez choisir le nombre de blocs à résumer dans une plage. Si vous diminuez ce nombre, l'index sera plus volumineux mais offrira probablement de meilleures performances.

Pour que le BRIN soit efficace, les données de la table doivent être stockées dans un ordre physique qui minimise le chevauchement de l'étendue du bloc. Il se peut que les données soient déjà triées de manière appropriée (par exemple, si elles sont chargées à partir d'un autre jeu de données déjà trié dans l'ordre spatial). Dans le cas contraire, il est possible de trier les données en fonction d'une clé spatiale unidimensionnelle. Une façon de procéder consiste à créer une nouvelle table triée par les valeurs géométriques (qui, dans les versions récentes de PostGIS, utilisent un classement efficace par courbe de Hilbert) :

CREATE TABLE table_sorted AS
   SELECT * FROM table  ORDER BY geom;

Il est également possible de trier les données en place en utilisant un GeoHash comme index (temporaire) et en effectuant un regroupement sur cet index :

CREATE INDEX idx_temp_geohash ON table
    USING btree (ST_GeoHash( ST_Transform( geom, 4326 ), 20));
CLUSTER table USING idx_temp_geohash;

La syntaxe pour construire un index BRIN sur une colonne geometry est la suivante :

CREATE INDEX [indexname] ON [tablename] USING BRIN ( [geome_col] ); 

La syntaxe ci-dessus permet de créer un index en 2D. Pour construire un index à trois dimensions, utilisez la syntaxe suivante :

CREATE INDEX [indexname] ON [tablename]
    USING BRIN ([geome_col] brin_geometry_inclusion_ops_3d);

Vous pouvez également obtenir un index quadridimensionnel à l'aide de la classe d'opérateurs 4D :

CREATE INDEX [indexname] ON [tablename]
    USING BRIN ([geome_col] brin_geometry_inclusion_ops_4d);

Les commandes ci-dessus utilisent le nombre par défaut de blocs dans une plage, qui est de 128. Pour spécifier le nombre de blocs à résumer dans une plage, utilisez la syntaxe suivante

CREATE INDEX [indexname] ON [tablename]
    USING BRIN ( [geome_col] ) WITH (pages_per_range = [number]); 

Gardez à l'esprit qu'un index BRIN ne stocke qu'une entrée d'index pour un grand nombre de lignes. Si votre table stocke des géométries avec un nombre variable de dimensions, il est probable que l'index qui en résultera sera peu performant. Vous pouvez éviter cette pénalité de performance en choisissant la classe d'opérateur avec le plus petit nombre de dimensions des géométries stockées

Le type de données geography est pris en charge pour l'indexation BRIN. La syntaxe pour construire un index BRIN sur une colonne géographique est la suivante :

CREATE INDEX [indexname] ON [tablename] USING BRIN ( [geog_col] ); 

La syntaxe ci-dessus permet de créer un index 2D pour les objets géospatiaux sur le sphéroïde.

Actuellement, seul le "support d'inclusion" est fourni, ce qui signifie que seuls les opérateurs &&, ~ et @ peuvent être utilisés pour les cas 2D (à la fois pour geometry et geography), et seulement l'opérateur &&& pour les géométries 3D. Il n'y a actuellement pas de support pour les recherches kNN.

Une différence importante entre BRIN et les autres types d'index est que la base de données ne maintient pas l'index de manière dynamique. Les modifications apportées aux données spatiales de la table sont simplement ajoutées à la fin de l'index. Cela entraîne une dégradation des performances de recherche de l'index au fil du temps. L'index peut être mis à jour en effectuant un VACUUM, ou en utilisant une fonction spéciale brin_summarize_new_values(regclass). C'est la raison pour laquelle BRIN peut être plus approprié pour les données qui sont en lecture seule ou qui ne changent que rarement. Pour plus d'informations, consultez le manuel.

En résumé, l'utilisation de BRIN pour les données spatiales :

  • Le temps de construction de l'index est très rapide et la taille de l'index est très réduite.

  • Le temps d'interrogation de l'index est plus lent que celui de GiST, mais reste très acceptable.

  • Nécessite que les données du tableau soient triées dans un ordre spatial.

  • Nécessite une maintenance manuelle de l'index.

  • Plus approprié pour les tables de très grande taille, avec peu ou pas de chevauchement (par exemple des points), qui sont statiques ou qui changent peu souvent.

  • Plus efficace pour les requêtes qui renvoient un nombre relativement important d'enregistrements de données.

4.9.3. Index SP-GiST

SP-GiST signifie "Space-Partitioned Generalized Search Tree" et est une forme générique d'indexation pour les types de données multidimensionnelles qui prend en charge les arbres de recherche partitionnés, tels que les arbres quadratiques, les arbres k-d et les arbres radix (tries). La caractéristique commune de ces structures de données est qu'elles divisent de manière répétée l'espace de recherche en partitions qui ne sont pas nécessairement de taille égale. Outre l'indexation spatiale, SP-GiST est utilisé pour accélérer les recherches sur de nombreux types de données, telles que le routage téléphonique, le routage ip, la recherche de substrats, etc. Pour plus d'informations, voir le manuel PostgreSQL.

Comme pour les index GiST, les index SP-GiST sont avec perte, dans le sens où ils stockent la boîte englobante qui entoure les objets spatiaux. Les index SP-GiST peuvent être considérés comme une alternative aux index GiST.

Lorsqu'une table de données SIG dépasse quelques milliers de lignes, un index SP-GiST peut être utilisé pour accélérer les recherches spatiales dans les données. La syntaxe pour construire un index SP-GiST sur une colonne "géométrie" est la suivante :

CREATE INDEX [indexname] ON [tablename] USING SPGIST ( [geometryfield] ); 

La syntaxe ci-dessus permet de créer un index bidimensionnel. Un index tridimensionnel pour le type de géométrie peut être créé à l'aide de la classe d'opérateurs 3D :

CREATE INDEX [indexname] ON [tablename] USING SPGIST ([geometryfield] spgist_geometry_ops_3d);

La création d'un index spatial est une opération très gourmande en ressources informatiques. Elle bloque également l'accès en écriture à votre table pendant la durée de la création, donc sur un système de production, vous voudrez peut-être le faire d'une manière plus lente, en tenant compte de la notion de CONCURRENCE :

CREATE INDEX CONCURRENTLY [indexname] ON [tablename] USING SPGIST ( [geometryfield] ); 

Après avoir construit un index, il est parfois utile de forcer PostgreSQL à collecter les statistiques de la table, qui sont utilisées pour optimiser les plans de requête :

VACUUM ANALYZE [table_name] [(column_name)];

Un index SP-GiST peut accélérer les requêtes impliquant les opérateurs suivants :

  • <<, &<, &>, >>, <<|, &<|, |&>, |>>, &&, @>, <@, et ~=, pour les index à 2 dimensions,

  • &/&, ~==, @>>, et <<@, pour les index à 3 dimensions.

Il n'y a pas de support pour les recherches kNN pour le moment.

4.9.4. Optimisation de l'utilisation de l'index

Normalement, les index accélèrent de manière invisible l'accès aux données : une fois qu'un index est construit, le planificateur de requêtes de PostgreSQL décide automatiquement quand l'utiliser pour améliorer les performances de la requête. Mais dans certaines situations, le planificateur ne choisit pas d'utiliser les index existants, et les requêtes finissent par utiliser des balayages séquentiels lents au lieu d'un index spatial.

Si vous constatez que vos index spatiaux ne sont pas utilisés, il y a plusieurs choses que vous pouvez faire :

  • Examinez le plan de requête et vérifiez que votre requête calcule effectivement ce dont vous avez besoin. Un JOIN erroné, oublié ou vers la mauvaise table, peut récupérer plusieurs fois des enregistrements de la table de manière inattendue. Pour obtenir le plan de la requête, exécutez avec EXPLAIN devant la requête.

  • Assurez-vous que des statistiques sont collectées sur le nombre et la distribution des valeurs dans une table, afin de fournir au planificateur de requêtes de meilleures informations pour prendre des décisions concernant l'utilisation de l'index. La VACUUM ANALYZE calculera les deux.

    Vous devriez de toute façon vacuum régulièrement vos bases de données. De nombreux administrateurs de bases de données PostgreSQL exécutent VACUUM en tant que tâche cron en dehors des heures de pointe sur une base régulière.

  • Si vacuum ne suffit pas, vous pouvez temporairement forcer le planificateur à utiliser les informations d'index en utilisant la commande SET ENABLE_SEQSCAN TO OFF;. De cette façon, vous pouvez vérifier si le planificateur est capable de générer un plan de requête accéléré par l'index pour votre requête. Vous ne devez utiliser cette commande qu'à des fins de débogage ; en règle générale, le planificateur sait mieux que vous quand utiliser les index. Une fois que vous avez exécuté votre requête, n'oubliez pas de lancer la commande SET ENABLE_SEQSCAN TO ON; afin que le planificateur fonctionne normalement pour les autres requêtes.

  • Si SET ENABLE_SEQSCAN TO OFF; aide votre requête à s'exécuter plus rapidement, votre Postgres n'est probablement pas adapté à votre matériel. Si vous trouvez que le planificateur se trompe sur le coût des balayages séquentiels par rapport aux balayages d'index, essayez de réduire la valeur de RANDOM_PAGE_COST dans postgresql.conf, ou utilisez SET RANDOM_PAGE_COST TO 1.1;. La valeur par défaut de RANDOM_PAGE_COST est 4.0. Essayez de la fixer à 1.1 (pour les disques SSD) ou à 2.0 (pour les disques magnétiques rapides). En diminuant la valeur, le planificateur est plus enclin à utiliser les balayages d'index.

  • Si la SET ENABLE_SEQSCAN TO OFF; n'aide pas votre requête, il se peut qu'elle utilise une construction SQL que le planificateur Postgres n'est pas encore en mesure d'optimiser. Il peut être possible de réécrire la requête de manière à ce que le planificateur soit en mesure de la traiter. Par exemple, une sous-requête avec un SELECT en ligne peut ne pas produire un plan efficace, mais peut être réécrite en utilisant un JOIN LATERAL.

Pour plus d'informations, voir la section du manuel Postgres sur Query Planning.