Réponse courte
Un index spatial est un arbre de boîtes englobantes d'entités qui permet à un moteur SIG de répondre à « qu'y a-t-il à proximité ? » sans lire chaque entité. Sans lui, une requête comme « donne-moi les parcelles intersectant cette vue cartographique » force un balayage séquentiel : le moteur teste la géométrie des 2 millions de parcelles même si 50 sont pertinentes. Avec un index R-tree ou GiST, il restreint d'abord aux quelques centaines dont les boîtes englobantes recoupent la vue, puis n'exécute le coûteux test géométrique exact que sur celles-là. Sur de grandes couches, c'est la différence entre des millisecondes et des minutes.
Différents conteneurs implémentent cela différemment — un .qix annexe pour les shapefiles, un R-tree interne pour le GeoPackage, un index GiST dans PostGIS — mais le principe est identique et le mode de défaillance est identique : un index manquant ou périmé fait ramper les requêtes spatiales.
Comment fonctionne réellement un index spatial
Les géométries sont arbitrairement complexes — un polygone de littoral peut avoir 100 000 sommets. Tester si deux tels polygones s'intersectent est coûteux en calcul. Un index spatial contourne l'essentiel de ce travail avec une stratégie en deux phases :
- Filtrer (l'index). Chaque entité est réduite à son rectangle englobant minimal (MBR) — quatre nombres. Ces rectangles sont organisés en un arbre hiérarchique (un R-tree : des rectangles regroupés en rectangles parents, récursivement). Pour trouver les entités proches d'une fenêtre de requête, le moteur parcourt l'arbre, élaguant des branches entières dont le rectangle parent ne peut recouvrir la fenêtre. Cela renvoie un petit ensemble de candidats.
- Affiner (la géométrie). Ce n'est que pour les candidats que le moteur exécute le prédicat exact (
ST_Intersects,ST_Contains, etc.) sur la géométrie complète.
L'index ne donne jamais la réponse finale à lui seul — il fournit une présélection peu coûteuse. C'est pourquoi « l'index n'est que des boîtes englobantes » n'est pas une faiblesse ; c'est tout l'intérêt.
PostGIS : les index GiST
PostGIS construit les index spatiaux à l'aide du cadre GiST (Generalized Search Tree) de PostgreSQL, qui implémente un R-tree sur les boîtes englobantes de géométrie.
CREATE INDEX idx_parcels_geom ON parcels USING GIST (geom);
ANALYZE parcels;
L'étape ANALYZE n'est pas facultative : le planificateur de requêtes a besoin de statistiques à jour pour choisir l'index plutôt qu'un balayage séquentiel. Après un chargement massif, analysez toujours.
Pour confirmer que l'index est utilisé, enveloppez la requête dans EXPLAIN ANALYZE :
EXPLAIN ANALYZE
SELECT id FROM parcels
WHERE ST_Intersects(geom, ST_MakeEnvelope(500000, 4600000, 501000, 4601000, 32630));
Cherchez Index Scan using idx_parcels_geom ou Bitmap Index Scan. Si vous voyez Seq Scan, l'index est manquant, périmé, ou le prédicat n'est pas indexable (une cause fréquente : envelopper geom dans une fonction comme ST_Buffer(geom, ...) du côté gauche de la comparaison, ce qui annule l'index). Pour de très grandes tables, envisagez aussi les index BRIN lorsque les données sont triées spatialement, et rappelez-vous que les index GiST utilisent la boîte englobante, donc le SRID doit correspondre entre la colonne et l'enveloppe de requête.
GeoPackage : R-tree interne
GeoPackage est une norme OGC bâtie sur un conteneur SQLite. Son index spatial est un R-tree implémenté sous forme de tables virtuelles SQLite (le module rtree), stocké à l'intérieur du fichier .gpkg aux côtés de déclencheurs qui maintiennent l'index synchronisé à mesure que les entités changent. C'est un véritable avantage sur les shapefiles : l'index voyage avec les données dans un fichier unique.
GDAL crée le R-tree par défaut lorsque vous écrivez un GeoPackage. Vous pouvez en ajouter un explicitement avec la fonction d'extension GeoPackage gpkgAddSpatialIndex, et vous pouvez vérifier son existence en interrogeant les métadonnées :
SELECT * FROM gpkg_extensions WHERE extension_name = 'gpkg_rtree_index';
Lorsque vous convertissez en GeoPackage avec ogr2ogr, l'index spatial est construit automatiquement ; pour être explicite :
ogr2ogr -f GPKG out.gpkg in.shp -lco SPATIAL_INDEX=YES
Shapefiles : fichiers d'index annexes
Un shapefile est un ensemble de fichiers frères (.shp géométrie, .shx index de formes, .dbf attributs, .prj SCR). Le .shx n'est pas un index spatial — c'est un index de décalage d'enregistrements permettant un accès rapide par numéro d'enregistrement. L'index spatial réel est un fichier annexe distinct :
.qix— l'index quadtree ouvert utilisé par GDAL/OGR, QGIS et MapServer..sbn/.sbx— l'index spatial propriétaire d'Esri.
Sans un .qix (ou .sbn), chaque requête spatiale sur le shapefile balaie tout le .shp. Construisez un .qix avec GDAL :
ogrinfo -sql "CREATE SPATIAL INDEX ON parcels" parcels.shp
Dans QGIS, c'est Propriétés de la couche → Source → Créer un index spatial. Comme l'index est un fichier distinct, il est facile à perdre : copiez uniquement .shp/.shx/.dbf/.prj dans un nouveau dossier et l'index a disparu, et un shapefile édité peut laisser un .qix périmé qui ne correspond plus à la géométrie. Cette fragilité est l'un des arguments pratiques les plus forts en faveur de GeoPackage plutôt que de shapefile.
GeoJSON et autres formats texte
GeoJSON (RFC 7946, longitude-latitude WGS84) n'a aucun index spatial intégré. C'est un flux de texte brut, donc toute requête charge et analyse l'intégralité du fichier. C'est acceptable pour quelques milliers d'entités sur une carte web, mais un mauvais choix pour des jeux de données analytiques ou volumineux — ceux-ci ont leur place dans GeoPackage, PostGIS ou un format tuilé (tuiles vectorielles, FlatGeobuf, qui porte un R-tree compacté optionnel). Si vous devez interroger de façon répétée un GeoJSON volumineux, chargez-le d'abord dans PostGIS ou convertissez-le en GeoPackage.
Exemple détaillé : pourquoi cela compte
Une couche de parcelles de 1,8 million d'entités, interrogeant les parcelles d'un seul pâté de maisons :
- GeoJSON, sans index : analyse des 1,8 M d'entités, ~dizaines de secondes, mémoire élevée.
- Shapefile, sans
.qix: balayage séquentiel du.shp, plusieurs secondes. - Shapefile avec
.qix: le quadtree restreint à quelques centaines de candidats, moins d'une seconde. - GeoPackage avec R-tree : filtre R-tree à l'intérieur de SQLite, moins d'une seconde, fichier portable unique.
- PostGIS avec GiST + ANALYZE : Bitmap Index Scan, millisecondes, et passage à l'échelle pour des utilisateurs concurrents.
La géométrie n'a jamais changé. Seul le chemin d'accès l'a fait.
Assurance qualité et validation avant remise
- PostGIS : confirmez que
CREATE INDEX ... USING GISTexiste (\d tabledans psql), que vous avez exécutéANALYZE, et queEXPLAIN ANALYZEmontre un balayage d'index sur des requêtes réelles. - GeoPackage : confirmez que les tables virtuelles
rtree_*existent et quegpkg_extensionsrépertoriegpkg_rtree_index. - Shapefile : confirmez qu'un
.qixse trouve à côté du.shp, et qu'il a été reconstruit après la dernière édition (un index périmé renvoie silencieusement de mauvais candidats). - Faites correspondre les SRID : un index sur une géométrie EPSG:32630 interrogé avec une enveloppe 4326 ne renvoie rien d'utile — confirmez que le SCR de la requête correspond à celui de la colonne.
Pièges courants et leurs causes
.qixpérimé ou manquant. Des shapefiles ont été copiés sans le fichier annexe, ou édités sans reconstruction. La requête « fonctionne » mais est lente, ou renvoie des candidats périmés. Reconstruisez-le.- Oublier
ANALYZEdans PostGIS. L'index existe mais le planificateur, faute de statistiques, choisit encore un balayage séquentiel. ExécutezANALYZE. - Fonctions sur la colonne indexée.
WHERE ST_Buffer(geom, 10) && ...ne peut pas utiliser l'index GiST ; tamponnez plutôt la géométrie de requête, en laissantgeombrut à gauche. - Indexer du GeoJSON. Il ne peut pas être indexé sur place ; migrez vers un conteneur indexé.
- Supposer que
.shxest l'index spatial. Ce n'est pas le cas. Il vous faut quand même.qix.
Le point de vue de Bathyl
Nous considérons l'index spatial comme une partie du livrable, et non comme un détail interne, car une couche non indexée qui s'ouvre sans problème sur le bureau s'effondre dès qu'elle alimente une carte web ou une base de données multi-utilisateurs. Choisir GeoPackage ou PostGIS plutôt que des shapefiles épars est en grande partie une décision de garder l'index avec les données pour qu'il ne puisse pas se perdre en transit.
À lire aussi chez Bathyl
- KML vs GeoJSON pour le partage de données spatiales
- Les tuiles vectorielles pour les cartes web
- Shapefile vs GeoPackage vs GeoJSON
- Produits de données spatiales