La fonction amcostestimate se voit donner des informations décrivant un parcours d'index possible, incluant des listes de clauses WHERE et ORDER BY qui ont été déterminées pour être utilisables avec l'index. Elle doit renvoyer une estimation du coût de l'accès à l'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 standard dans l'optimiseur ; la raison d'avoir une fonction amcostestimate est d'autoriser les méthodes d'accès aux index à fournir une connaissance spécifique au type d'index, au cas où il serait possible d'améliorer les estimations standard.
Chaque fonction amcostestimate doit avoir la signature :
void amcostestimate (PlannerInfo *root, IndexPath *path, double loop_count, Cost *indexStartupCost, Cost *indexTotalCost, Selectivity *indexSelectivity, double *indexCorrelation);
Les trois premiers paramètres sont des entrées :
Information du planificateur sur la requête en cours de traitement.
Le chemin d'accès considéré pour l'index. Tous les champs, en dehors du coût et de la sélectivité, sont valides.
Le nombre de répétitions du parcours d'index qui devrait être pris en compte dans les estimations de coût. Cela sera généralement supérieur à 1 lors d'un parcours avec paramètres à utiliser à l'intérieur d'une jointure de boucle imbriquée. Notez que l'estimation de coût doit toujours être pour un seul parcours ; une valeur plus importante de loop_count signifie qu'il pourrait être approprié de permettre des effets de cache avec plusieurs parcours.
Les quatre derniers paramètres sont les sorties passées par référence :
Initialisé au coût du lancement du traitement de l'index.
Initialisé au coût du traitement total de l'index.
Initialisé à la sélectivité de l'index.
Initialisé au coefficient de corrélation entre l'ordre du parcours de l'index et l'ordre sous-jacent de la table.
Les fonctions d'estimation de coûts doivent être écrites en C, pas en SQL ou dans tout 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 total de parcours à dépenser avant de commencer à récupérer la première ligne. Pour la plupart des index, cela s'évalue à zéro, mais un type d'index avec un grand coût de lancement peut vouloir le configurer à une autre valeur que zéro.
indexSelectivity doit être initialisé à la fraction estimée des lignes de la table parent qui sera récupérée lors du parcours d'index. Dans le cas d'une requête à perte, c'est typiquement plus élevé que la fraction des lignes qui satisfont les conditions de qualification données.
indexCorrelation doit ê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 du coût de récupération des lignes de la table parent.
Quand loop_count est supérieur à 1, les nombres renvoyés doivent être des moyennes attendues pour tout parcours de l'index.
Procédure 58.1. Estimation du coût
Un estimateur typique de coût exécute le traitement ainsi :
Estime et renvoie la fraction des lignes de la table parent visitées d'après les conditions de qualification données. En l'absence de toute connaissance spécifique sur le type de l'index, on utilise la fonction de l'optimiseur standard clauselist_selectivity():
+*indexSelectivity = clauselist_selectivity(root, path->indexquals, + path->indexinfo->rel->relid, JOIN_INNER, NULL);
Estime le nombre de lignes d'index visitées lors du parcours. Pour de nombreux types d'index, il s'agit de indexSelectivity multiplié par le nombre de lignes dans l'index, mais cela peut valoir plus (la taille de l'index en pages et lignes est disponible à partir de la structure path->indexinfo).
Estime le nombre de pages d'index récupérées pendant le parcours. Ceci peutt être simplement indexSelectivity multiplié par la taille de l'index en pages.
Calcule le coût d'accès à l'index. Un estimateur générique peut 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, path->indexquals, root); *indexStartupCost = index_qual_cost.startup; *indexTotalCost = seq_page_cost * numIndexPages + (cpu_index_tuple_cost + index_qual_cost.per_tuple) * numIndexTuples;
Néanmoins, le calcul ci-dessus ne prend pas en compte l'amortissement des lectures des index à travers les parcours répétés d'index.
Estime la corrélation de l'index. Pour un index ordonné sur un seul champ, cela peut s'extraire 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.