49.6. Fonctions d'estimation des coûts d'index
La fonction amcostestimate se voit donner une liste de clauses WHERE
qui ont été déterminées pour être utilisables avec l'index. Il doit
renvoyer une estimation du coût de l'accès d'index et de la
sélectivité des clauses WHERE (c'est-à-dire la fraction des lignes de
la table parent qui seront récupérées lors du parcours de l'index).
Pour les cas simples, pratiquement tout le travail de l'estimateur de
coût peut être effectué en appelant des routines standards dans
l'optimiseur ; la raison d'avoir une fonction amcostestimate est
d'autoriser les méthodes d'accès aux index pour fournir une
connaissance spécifique au type d'index, au cas où il est possible
d'améliorer les estimations standards.
Chaque fonction amcostestimate doit avoir la signature :
void
amcostestimate (PlannerInfo *root,
IndexOptInfo *index,
List *indexQuals,
RelOptInfo *outer_rel,
Cost *indexStartupCost,
Cost *indexTotalCost,
Selectivity *indexSelectivity,
double *indexCorrelation);
Les quatre premiers paramètres sont des entrées :
-
root
-
Information du planificateur sur la requête en cours de
traitement.
-
index
-
Index considéré.
-
indexQuals
-
Liste des clauses qual d'index (implicitement assemblées avec
des AND) ; une liste NIL indique qu'aucun qualificateur n'est
disponible. Notez que la liste contient des arbres
d'expression, pas ScanKeys.
-
outer_rel
-
Si l'utilisation de l'index est considérée dans un parcours
d'index pour une jointure interne, le planificateur dispose des
informations sur le côté externe de la jointure. Sinon NULL.
Quand non NULL, certaines des clauses qual seront des clauses
de jointure avec cette relation plutôt que de simples clauses
de restriction. De plus, le processus d'estimation du coût
devrait s'attendre à ce que le parcours d'index soit répété
pour chaque ligne de la relation externe.
Les quatre derniers paramètres sont passés par leur référence :
-
*indexStartupCost
-
Initialisé au coût du lancement du traitement de l'index
-
*indexTotalCost
-
Initialisé au coût du traitement total par l'index
-
*indexSelectivity
-
Initialisé à la sélectivité de l'index
-
*indexCorrelation
-
Initialisé au coefficient de corrélation entre l'ordre du
parcours de l'index et l'ordre sous-jacent de la table
Notez que les fonctions d'estimation de coûts doivent être écrits en
C, pas en SQL ou dans un autre langage de procédure, parce qu'elles
doivent accéder aux structures de données internes du
planificateur/optimiseur.
Les coûts d'accès aux index doivent être calculés en utilisant les
paramètres utilisés par src/backend/optimizer/path/costsize.c : la
récupération d'un bloc disque séquentiel a un coût de seq_page_cost, une récupération non séquentielle a un
coût de random_page_cost, et le coût de
traitement d'une ligne d'index doit habituellement être considéré
comme cpu_index_tuple_cost. De plus, un
multiple approprié de cpu_operator_cost doit
être chargé pour tous les opérateurs de comparaison impliqués lors du
traitement de l'index (spécialement l'évaluation des indexQuals).
Les coûts d'accès doivent inclure tous les coûts dûs aux disques et
aux CPU associés au parcours d'index lui-même, mais
pas
les coûts de récupération ou de
traitement des lignes de la table parent qui sont identifiées par
l'index.
Le « coût de lancement » est la
partie du coût du parcours total devant être étendu avant que nous
commencions à récupérer la première ligne. Pour la plupart des index,
cela peut être considéré comme zéro mais un type d'index avec un
grand coût de lancement pourrait vouloir le configurer à une autre
valeur que zéro.
indexSelectivity devrait être initialisé à la fraction estimée des
lignes de la table parent qui seront récupérées lors du parcours
d'index. Au cas où il s'agit d'un index à perte, cela sera
typiquement plus haut que la fraction des lignes qui réussissent les
conditions qual données.
indexCorrelation devrait être initialisé à la corrélation (valeur
entre -1,0 et 1,0) entre l'ordre de l'index et celui de la table.
Cela permet d'ajuster l'estimation pour le coût de récupération des
lignes de la table parent.
Dans le cas de la jointure, les nombres renvoyés devraient être des
moyennes attendues pour tout parcours de l'index.
Procédure 49.1. Estimation du coût
Un estimateur typique de coût exécutera le traitement ainsi :
-
Estime et renvoie la fraction des lignes de la table parent qui
seront visitées suivant les conditions qual données. En
l'absence de toute connaissance spécifique sur le type de
l'index, utilisez la fonction de l'optimiseur standard
clauselist_selectivity():
*indexSelectivity = clauselist_selectivity(root, indexQuals,
index->rel->relid, JOIN_INNER);
-
Estime le nombre de lignes d'index qui seront visitées lors du
parcours. Pour de nombreux types d'index, ceci vaut
indexSelectivity fois le nombre de lignes dans l'index, mais
cela pourrait valoir plus (notez que la taille de l'index en
pages et lignes est disponible à partir de la structure
IndexOptInfo).
-
Estime le nombre de pages d'index qui seront récupérées pendant
le parcours. Ceci pourrait être simplement indexSelectivity
fois la taille de l'index en pages.
-
Calcule le coût d'accès à l'index. Un estimateur générique
pourrait le faire ainsi :
/*
* Our generic assumption is that the index pages will be read
* sequentially, so they have cost seq_page_cost each, not random_page_cost.
* Also, we charge for evaluation of the indexquals at each index row.
* All the costs are assumed to be paid incrementally during the scan.
*/
cost_qual_eval(&index_qual_cost, indexQuals);
*indexStartupCost = index_qual_cost.startup;
*indexTotalCost = seq_page_cost * numIndexPages +
(cpu_index_tuple_cost + index_qual_cost.per_tuple) * numIndexTuples;
Néanmoins, l'exemple ci-dessus ne prend pas en compte
l'amortissement des lectures des index via les parcours répétés
d'index dans le cas de la jointure.
-
Estime la corrélation de l'index. Pour un index ordonné sur un
seul champ, ceci peut se récupérer de pg_statistic. Si la
corrélation est inconnue, l'estimation conservative est zéro
(pas de corrélation).
Des exemples de fonctions d'estimation du coût sont disponibles dans
src/backend/utils/adt/selfuncs.c.