Documentation PostgreSQL 14.22 » Internes » Définition de l'interface des méthodes d'accès aux index » Structure basique de l'API pour les index

Précédent | Niveau supérieur | Suivant
Chapitre 62. Définition de l'interface des méthodes d'accès aux index | Sommaire | 62.2. Fonctions des méthodes d'accès aux index

## 62.1. Structure basique de l'API pour les index

Chaque méthode d'accès à un index est décrite par une ligne dans le catalogue système `pg_am`. Elle indique un nom et une fonction gestionnaire pour la méthode d'accès à l'index. Ces entrées peuvent être créées et supprimées en utilisant les commandes SQL CREATE ACCESS METHOD et DROP ACCESS METHOD respectivement.

Une fonction gestionnaire de méthode d'accès aux index doit être déclarée avec un seul argument de type `internal` et en retour le pseudo-type `index_am_handler`. L'argument est une valeur sans utilité sinon pour empêcher les fonctions gestionnaires d'être appelées directement à partir d'une commande SQL. Le résultat de la fonction doit être une structure, allouée avec palloc, de type `IndexAmRoutine`, et contenant tout ce que le code interne a besoin de savoir pour utiliser la méthode d'accès à l'index. La structure `IndexAmRoutine`, aussi appelée API struct de la méthode, inclut les champs spécifiant les propriétés fixes de la méthode d'accès, comme le support des index multi-colonnes. Plus important, elle contient les pointeurs vers les fonctions de la méthode d'accès, qui se chargent de tout le travail d'accès aux index. Ces fonctions de support sont de simples fonctions en C et ne sont ni visibles ni appelables au niveau SQL. Elles sont décrites dans Section 62.2.

La structure `IndexAmRoutine` est définie ainsi :

    typedef struct IndexAmRoutine
    {
        NodeTag     type;

        /*
         * Nombre total de stratégies (opérateurs) par lesquels nous pouvons
         * traverser la méthode d'accès ou chercher dedans. Zéro si la méthode
         * n'a pas de jeu de stratégies fixé.
         */
        uint16      amstrategies;
        /* nombre total de fonctions support utilisées par cette méthode d'accès */
        uint16      amsupport;
        /* opclass options support function number or 0 */
        uint16      amoptsprocnum;
        /* la méthode supporte-t-elle un ORDER BY sur la colonne indexée ? */
        bool        amcanorder;
        /* la méthode supporte-t-elle un ORDER BY sur le résultat d'un opérateur appliqué à une colonne indexée ? */
        bool        amcanorderbyop;
        /* la méthode supporte-t-elle le parcours à rebours ? */
        bool        amcanbackward;
        /* la méthode supporte-t-elle les index UNIQUE ? */
        bool        amcanunique;
        /* la méthode supporte-t-elle les index multi-colonnes ? */
        bool        amcanmulticol;
        /* la méthode exige-t-elle un parcours pour une contrainte sur la première colonne de l'index ? */
        bool        amoptionalkey;
        /* la méthode gère-t-elle les qualificatifs ScalarArrayOpExpr ? */
        bool        amsearcharray;
        /* la méthode gère-elle les qualificatifs IS NULL/IS NOT NULL ? */
        bool        amsearchnulls;
        /* le type de la valeur dans l'index peut-elle différer du type de la colonne ? */
        bool        amstorage;
        /* un index de ce type peut-il être la cible de la commande CLUSTER ? */
        bool        amclusterable;
        /* la méthode gère-t-elle les verrous sur prédicat ? */
        bool        ampredlocks;
        /* la méthode gère-t-elle les parcours parallélisés ? */
        bool        amcanparallel;
        /* la méthode gère-t-elle les colonnes incluses avec la clause INCLUDE ? */
        bool        amcaninclude;
        /* does AM use maintenance_work_mem? */
        bool        amusemaintenanceworkmem;
        /* OR of parallel vacuum flags */
        uint8       amparallelvacuumoptions;
        /* type de données stocké dans l'index, ou InvalidOid si variable */
        Oid         amkeytype;

        /* fonctions d'interfaçage */
        ambuild_function ambuild;
        ambuildempty_function ambuildempty;
        aminsert_function aminsert;
        ambulkdelete_function ambulkdelete;
        amvacuumcleanup_function amvacuumcleanup;
        amcanreturn_function amcanreturn;   /* peut être NULL */
        amcostestimate_function amcostestimate;
        amoptions_function amoptions;
        amproperty_function amproperty;     /* peut être NULL */
        ambuildphasename_function ambuildphasename;   /* peut être NULL */
        amvalidate_function amvalidate;
        amadjustmembers_function amadjustmembers; /* peut être NULL */
        ambeginscan_function ambeginscan;
        amrescan_function amrescan;
        amgettuple_function amgettuple;     /* peut être NULL */
        amgetbitmap_function amgetbitmap;   /* peut être NULL */
        amendscan_function amendscan;
        ammarkpos_function ammarkpos;       /* peut être NULL */
        amrestrpos_function amrestrpos;     /* peut être NULL */

        /* interface functions to support parallel index scans */
        amestimateparallelscan_function amestimateparallelscan;    /* can be NULL */
        aminitparallelscan_function aminitparallelscan;    /* can be NULL */
        amparallelrescan_function amparallelrescan;    /* can be NULL */
    } IndexAmRoutine;

Pour être utile, une méthode d'accès à l'index doit aussi avoir une ou plusieurs familles d'opérateurs et classes d'opérateurs définies dans `pg_opfamily`, `pg_opclass`, `pg_amop` et `pg_amproc`. Ces entrées permettent au planificateur de déterminer les types de requêtes qui peuvent être utilisés avec les index de cette méthode d'accès. Les familles et classes d'opérateurs sont décrites dans Section 38.16, qui est un élément requis pour comprendre ce chapitre.

Un index individuel est défini par une entrée dans `pg_class` en tant que relation physique, et une entrée dans `pg_index` affichant son contenu logique -- c'est-à-dire ses colonnes et leur sémantique, telles que récupérées par les classes d'opérateurs associées. Les colonnes de l'index (valeurs clés) peuvent être de simples colonnes de la table sous-jacente ou des expressions des lignes. Habituellement, la méthode d'accès ne s'intéresse pas à la provenance des valeurs clés (elles lui arrivent toujours pré-calculées), mais plutôt aux informations de la classe d'opérateurs dans `pg_index`. On peut accéder aux entrées de ces deux catalogues via la structure de données `Relation` passée à toute opération sur l'index.

Certains champs de `IndexAmRoutine` ont des implications peu évidentes. Les besoins de `amcanunique` sont discutés dans Section 62.5. L'option `amcanmulticol` indique que la méthode d'accès supporte les index à clés multi-colonnes alors que `amoptionalkey` autorise des parcours lorsqu'aucune restriction indexable n'est fournie pour la première colonne de l'index. Quand `amcanmulticol` est faux, `amoptionalkey` indique essentiellement que la méthode d'accès autorise les parcours complets de l'index sans clause de restriction. Les méthodes d'accès supportant les colonnes multiples doivent supporter les parcours sans restriction sur une ou toutes les colonnes après la première ; néanmoins, elles peuvent imposer une restriction sur la première colonne de l'index, ce qui est signalé par `amoptionalkey` à false . Une raison pour une méthode d'accès d'index d'initialiser `amoptionalkey` à false est de ne pas indexer les valeurs NULL. Comme la plupart des opérateurs indexables sont stricts et ne peuvent donc pas renvoyer true pour des entrées NULL, à première vue on ne voudra pas stocker d'entrées pour les valeurs NULL : un parcours d'index ne peut de toute façon pas les retourner. Néanmoins, cette raison ne vaut pas pour un parcours d'index sans restriction pour une colonne d'index donnée. En pratique, cela signifie que les index avec `amoptionalkey` à true doivent indexer les valeurs NULL, car le planificateur peut décider de les utiliser sans aucune clé de parcours. Une limite liée : une méthode d'accès qui supporte des colonnes multiples doit supporter l'indexation des NULL dans les colonnes après la première, car le planificateur supposera l'index utilisable avec les requêtes ne restreignant pas ces colonnes. Par exemple, considérons un index sur (a,b) et une requête avec `WHERE a = 4`. Le système supposera que l'index est utilisable pour les lignes où `a = 4`, ce qui est faux si l'index omet les lignes où `b` est NULL. Néanmoins, on peut omettre les lignes où la première colonne indexée est NULL. Du coup, une méthode d'accès d'index ne s'occupant pas des valeurs NULL peut aussi affecter `amsearchnulls` à true, indiquant ainsi qu'elle supporte les clauses `IS NULL` et `IS NOT NULL` dans les conditions de recherche.

L'option `amcaninclude` indique si la méthode d'accès supporte les colonnes « included », c'est-à-dire qu'elle peut enregistrer (sans traiter) des colonnes supplémentaires en dehors des colonnes clés. En particulier, la combinaison de `amcanmulticol`=`false` et de `amcaninclude`=`true` est sensible : cela signifie qu'il peut seulement y avoir une colonne clé, mais qu'il peut y avoir une ou plusieurs colonnes inclues. De plus, les colonnes inclues doivent être autorisées à être configurées à NULL, indépendemment de `amoptionalkey`.