Chapitre 49. Fonctions d'estimation du coût des index

Auteur : Écrit par Tom Lane () le 24 janvier 2000.

Note : Ceci pourra faire partie d'un futur chapitre plus étoffé sur la façon d'écrire des nouvelles méthodes d'accès aux index.

Chaque méthode d'accès aux index doit fournir une fonction d'estimation de coût qui est utilisée par l'optimiseur de requêtes. L'OID de procédure de cette fonction est donné dans le champ amcostestimate de la ligne correspondant à cette méthode d'accès dans la table pg_am.

Note : Avant PostgreSQL 7.0, un mécanisme différent était utilisé pour enregistrer les fonctions d'estimation de coût spécifiques des index.

La fonction amcostestimate reçoit en paramètres une liste de clauses WHERE pour lesquelles il a été déterminé qu'elles peuvent utiliser cet index. Elle doit retourner le coût estimé d'accès à l'index et la sélectivité de la clause WHERE, c'est-à-dire la fraction de la table principale qui sera retournée par le parcours de l'index. Dans les cas simples, pratiquement tout le travail d'estimation de coût peut être réalisé en appelant des routines standard de l'optimiseur ; La fonction amcostestimate ne sert qu'à permettre à la méthode d'accès d'ajouter sa connaissance spécifique du type d'index, au cas où il serait possible d'améliorer l'estimation standard.

Chaque fonction amcostestimate doit avoir la signature suivante :

void
amcostestimate (Query *root,
                RelOptInfo *rel,
                IndexOptInfo *index,
                List *indexQuals,
                Cost *indexStartupCost,
                Cost *indexTotalCost,
                Selectivity *indexSelectivity,
                double *indexCorrelation);
   

Les quatre premiers paramètres sont des entrées :

root

La requête traitée.

rel

La relation sur laquelle porte l'index.

index

L'index lui même.

indexQuals

La liste des clauses qualifiées pour l'index (implicitement reliées par des ET logiques) ; une liste NIL indique qu'aucune clause n'est qualifiée.

Les quatre derniers paramètres sont des sorties passées par référence :

*indexStartupCost

Coût du démarrage du traitement de l'index

*indexTotalCost

Coût total de traitement de l'index

*indexSelectivity

Sélectivité de l'index

*indexCorrelation

Coefficient de corrélation entre l'ordre de lecture de l'index et l'ordre de la table sous-jacente.

Notez que les fonctions d'estimation de coût doivent être écrites en C, pas en SQL ou avec un autre des langages de programmation disponibles, car elles doivent accéder aux structures de données internes de l'optimiseur.

Le coût d'accès aux index doit être calculé avec les unités utilisées dans src/backend/optimizer/path/costsize.c : la lecture séquentielle d'un bloc a un coût de 1,0, une lecture non séquentielle a un coût de random_page_cost et le coût de traitement d'une ligne d'index a généralement un coût de cpu_index_tuple_cost (qui est un paramètre réglable par l'utilisateur). De plus, un multiple approprié de cpu_operator_cost doit être ajouté pour chaque opérateur de comparaison appelé lors du traitement de l'index et, spécialement, pour l'évaluation des indexQuals eux-mêmes.

Le coût d'accès doit inclure chaque coût disque et CPU associé au parcours de l'index lui même, mais PAS les coûts associés à la recherche ou au traitement des lignes de la table principale qui sont identifiées par l'index.

Le << coût de départ >> est la part du coût total de parcours qui doit être dépensée avant de pouvoir retrouver la première ligne. Pour la plupart des index, il peut être mis à zéro, mais un index qui a un coût de départ élevé peut vouloir lui donner un coût supérieur à zéro.

La sélectivité de l'index indexSelectivity doit indiquer la fraction de la table principale qui sera retournée par le parcours de l'index. Dans le cas d'un index peu intéressant, la sélectivité sera typiquement supérieure à la fraction des lignes qui passent réellement les conditions données.

indexCorrelation doit donner la corrélation (entre -1,0 et 1,0) entre l'ordre de l'index et l'ordre de la table. Ce paramètre est utilisé pour ajuster le coût de lecture de la table principale.

Estimation de coût

Une estimation de coût classique se fait comme suit :

  1. Estimez et retournez la fraction de la table principale qui sera visitée, en fonction des conditions qualifiés. En l'absence de connaissance spécifique au type d'index, utilisez la fonction standard de l'optimiseur, clauselist_selectivity() :

    *indexSelectivity = clauselist_selectivity(root, indexQuals,
                                               rel- relid, JOIN_INNER);
         

  2. Estimez le nombre de lignes d'index qui seront visitées durant le parcours. Pour de nombreux types d'index, cette valeur vaut indexSelectivity fois le nombre de lignes de l'index mais elle peut valoir plus. (Notez que la taille de l'index en pages et en lignes et disponible dans la structure IndexOptInfo.)

  3. Estimez le nombre de pages d'index qui seront retournées lors de son parcours. Ce sera peut-être juste indexSelectivity fois la taille de l'index en pages.

  4. Calculez le coût d'accès à l'index. Un estimateur générique pourrait procéder comme suit :

        /*
         * La supposition générale est que les pages d'index vont être lues
         * séquentiellement, si bien qu'elles ont un coût de 1,0 chacune, et
         * non pas de random_page_cost.
         * De plus, on ajoute le coût de l'évaluation des conditions pour chaque
         * ligne d'index. Tous les coûts sont supposés payés incrémentalement
         * lors du parcours de l'index.
         */
        cost_qual_eval(&index_qual_cost, indexQuals);
        *indexStartupCost = index_qual_cost.startup;
        *indexTotalCost = numIndexPages +
            (cpu_index_tuple_cost + index_qual_cost.per_tuple) * numIndexTuples;
         

  5. Estimez la corrélation d'index. Pour un index simple ordonné sur un seul champ, cela peut se retrouver dans pg_statistic. Si vous ne savez pas, mettez zéro (pas de corrélation).

Des exemples de fonctions d'estimation peuvent être trouvés dans src/backend/utils/adt/selfuncs.c.

Par convention, l'entrée dans pg_proc pour une fonction amcostestimate a huit arguments tous déclarés comme internal (car aucun n'a un type connu de SQL), et le type retourné est void.