PostgreSQLLa base de données la plus sophistiquée au monde.
Documentation PostgreSQL 18 beta 1 » Langage SQL » Index » Index multicolonnes

11.3. Index multicolonnes #

Un index peut porter sur plusieurs colonnes d'une table. Soit, par exemple, une table de la forme :

CREATE TABLE test2 (
  majeur int,
  mineur int,
  nom varchar
);

(cas d'un utilisateur gardant son répertoire /dev dans une base de données...) et que des requêtes comme :

SELECT nom FROM test2 WHERE majeur = constante AND mineur = constante;

sont fréquemment exécutées. Il peut alors être souhaitable de définir un index qui porte sur les deux colonnes majeur et mineur. Ainsi :

CREATE INDEX test2_mm_idx ON test2 (majeur, mineur);

Actuellement, seuls les types d'index B-tree, GiST, GIN et BRIN supportent les index multicolonnes. Qu'il puisse y avoir plusieurs colonnes clés est indépendant de si les colonnes INCLUDE peuvent être ajoutées à l'index. Les index peuvent avoir jusqu'à 32 colonnes en incluant les colonnes INCLUDE. Cette limite peut être modifiée à la compilation de PostgreSQL. Voir le fichier pg_config_manual.h.

Un index B-tree multicolonne peut être utilisé avec des conditions de requêtes impliquant un sous-ensemble quelconque de colonnes de l'index. L'index est toutefois plus efficace lorsqu'il y a des contraintes sur les premières colonnes (celles de gauche). La règle exacte est la suivante : les contraintes d'égalité sur les premières colonnes, et toute contrainte d'inégalité sur la première colonne qui ne possède pas de contrainte d'égalité sont utilisées pour limiter la partie parcourue de l'index. Les contraintes sur les colonnes à droite de ces colonnes are checked in the index, so they'll always save visits to the table proper, but they do not necessarily reduce the portion of the index that has to be scanned. If a B-tree index scan can apply the skip scan optimization effectively, it will apply every column constraint when navigating through the index via repeated index searches. This can reduce the portion of the index that has to be read, even though one or more columns (prior to the least significant index column from the query predicate) lacks a conventional equality constraint. Skip scan works by generating a dynamic equality constraint internally, that matches every possible value in an index column (though only given a column that lacks an equality constraint that comes from the query predicate, and only when the generated constraint can be used in conjunction with a later column constraint from the query predicate).

For example, given an index on (x, y), and a query condition WHERE y = 7700, a B-tree index scan might be able to apply the skip scan optimization. This generally happens when the query planner expects that repeated WHERE x = N AND y = 7700 searches for every possible value of N (or for every x value that is actually stored in the index) is the fastest possible approach, given the available indexes on the table. This approach is generally only taken when there are so few distinct x values that the planner expects the scan to skip over most of the index (because most of its leaf pages cannot possibly contain relevant tuples). If there are many distinct x values, then the entire index will have to be scanned, so in most cases the planner will prefer a sequential table scan over using the index.

The skip scan optimization can also be applied selectively, during B-tree scans that have at least some useful constraints from the query predicate.

Par exemple, avec un index sur (a, b, c) et une condition de requête WHERE a = 5 AND b >= 42 AND c < 77, the index might have to be scanned from the first entry with a = 5 and b = 42 up through the last entry with a = 5. Index entries with c >= 77 will never need to be filtered at the table level, but it may or may not be profitable to skip over them within the index. When skipping takes place, the scan starts a new index search to reposition itself from the end of the current a = 5 and b = N grouping (i.e. from the position in the index where the first tuple a = 5 AND b = N AND c >= 77 appears), to the start of the next such grouping (i.e. the position in the index where the first tuple a = 5 AND b = N + 1 appears).

Un index GiST multicolonne peut être utilisé avec des conditions de requête qui impliquent un sous-ensemble quelconque de colonnes de l'index. Les conditions sur des colonnes supplémentaires restreignent les entrées renvoyées par l'index, mais la condition sur la première colonne est la plus importante pour déterminer la part de l'index parcourue. Un index GiST est relativement inefficace si sa première colonne n'a que quelques valeurs distinctes, même s'il y a beaucoup de valeurs distinctes dans les colonnes supplémentaires.

Un index multicolonne GIN peut être utilisé avec des conditions de requête qui impliquent tout sous-ensemble des colonnes de l'index. Contrairement à B-tree ou GiST, la qualité de la recherche dans l'index est identique quelles que soient les colonnes de l'index que la requête utilise.

Un index BRIN multicolonne peut être utilisé avec des conditions dans la requête qui impliquent tout sous-ensemble de colonnes dans l'index. Comme GIN et contrairement à B-tree ou GiST, l'efficacité de la recherche par l'index est la même quelles que soient les colonnes utilisées dans les conditions de la requête. La seule raison d'avoir plusieurs index BRIN au lieu d'un index BRIN multicolonne sur une table est d'avoir un paramétrage de stockage pages_per_range différent.

Chaque colonne doit évidemment être utilisée avec des opérateurs appropriés au type de l'index ; les clauses qui impliquent d'autres opérateurs ne sont pas prises en compte.

Il est préférable d'utiliser les index multicolonnes avec parcimonie. Dans la plupart des cas, un index sur une seule colonne est suffisant et préserve espace et temps. Les index de plus de trois colonnes risquent fort d'être inefficaces, sauf si l'utilisation de cette table est extrêmement stylisée. Voir aussi la Section 11.5 et Section 11.9 pour les discussions sur les mérites des différentes configurations d'index.