A la función amcostestimate se le da información que describe
un escaneo de índice posible, incluyendo listas de cláusulas WHERE y ORDER BY que
se ha determinado que son utilizables con el índice. Debe devolver estimaciones
del costo de acceder al índice y la selectividad de las cláusulas WHERE
(es decir, la fracción de filas de la tabla padre que se recuperarán
durante el escaneo del índice). Para casos sencillos, casi todo el
trabajo del estimador de costos se puede realizar llamando a rutinas estándar
en el optimizador; el objetivo de tener una función amcostestimate es
permitir que los métodos de acceso a índices proporcionen conocimientos específicos del tipo de índice,
en caso de que sea posible mejorar las estimaciones estándar.
Cada función amcostestimate debe tener la firma:
void
amcostestimate (PlannerInfo *root,
IndexPath *path,
double loop_count,
Cost *indexStartupCost,
Cost *indexTotalCost,
Selectivity *indexSelectivity,
double *indexCorrelation,
double *indexPages);
Los primeros tres parámetros son entradas:
rootLa información del planificador sobre la consulta que se está procesando.
pathLa ruta de acceso al índice que se está considerando. Todos los campos, excepto los valores de costo y selectividad, son válidos.
loop_count
El número de repeticiones del escaneo del índice que se debe tener en cuenta
en las estimaciones de costos. Esto normalmente será mayor que uno cuando
se considera un escaneo parametrizado para su uso en el interior de una unión
de bucle anidado (nestloop join). Ten en cuenta que las estimaciones de costos deben seguir siendo para un solo escaneo;
un loop_count mayor significa que puede ser apropiado
permitir algunos efectos de almacenamiento en caché a través de múltiples escaneos.
Los últimos cinco parámetros son salidas por referencia:
*indexStartupCostEstablecido al costo del procesamiento de inicio del índice (startup cost).
*indexTotalCostEstablecido al costo total del procesamiento del índice.
*indexSelectivityEstablecido a la selectividad del índice.
*indexCorrelationEstablecido al coeficiente de correlación entre el orden de escaneo del índice y el orden de la tabla subyacente.
*indexPagesEstablecido al número de páginas hoja del índice.
Ten en cuenta que las funciones de estimación de costos deben escribirse en C, no en SQL o en cualquier lenguaje procedimental disponible, porque deben acceder a las estructuras de datos internas del planificador/optimizador.
Los costos de acceso al índice deben calcularse utilizando los parámetros utilizados por
src/backend/optimizer/path/costsize.c: la recuperación secuencial de un
bloque de disco tiene el costo seq_page_cost, una recuperación no secuencial
tiene el costo random_page_cost, y el costo de procesar una fila de
índice generalmente debe tomarse como cpu_index_tuple_cost. Además,
se debe cobrar un múltiplo adecuado de cpu_operator_cost por cualquier operador
de comparación invocado durante el procesamiento del índice (especialmente la evaluación de las propias
indexquals).
Los costos de acceso deben incluir todos los costos de disco y de CPU asociados con el escaneo del índice en sí, pero no los costos de recuperar o procesar las filas de la tabla padre identificadas por el índice.
El “costo de inicio” (start-up cost) es la parte del costo total del escaneo que debe gastarse antes de que podamos comenzar a recuperar la primera fila. Para la mayoría de los índices, esto se puede considerar como cero, pero un tipo de índice con un alto costo de inicio podría querer establecerlo en un valor distinto de cero.
El parámetro indexSelectivity debe establecerse en la fracción estimada de las filas de la tabla
padre que se recuperarán durante el escaneo del índice. En el caso de una consulta
con pérdidas, esto será típicamente más alto que la fracción de filas que
realmente pasan las condiciones cualificadoras dadas.
El parámetro indexCorrelation debe establecerse en la correlación (que varía entre
-1.0 y 1.0) entre el orden del índice y el orden de la tabla. Esto se usa
para ajustar la estimación del costo de recuperar filas de la tabla
padre.
El parámetro indexPages debe establecerse en el número de páginas hoja.
Esto se usa para estimar el número de trabajadores para el escaneo de índice en paralelo.
Cuando loop_count es mayor que uno, los números devueltos
deben ser los promedios esperados para cualquier escaneo individual del índice.
Estimación de costos
Un estimador de costos típico procederá de la siguiente manera:
Estima y devuelve la fracción de filas de la tabla padre que se visitarán
según las condiciones cualificadoras dadas. A falta de conocimientos específicos sobre el tipo de
índice, utiliza la función estándar del optimizador clauselist_selectivity():
*indexSelectivity = clauselist_selectivity(root, path->indexquals,
path->indexinfo->rel->relid,
JOIN_INNER, NULL);
Estima el número de filas de índice que se visitarán durante el
escaneo. Para muchos tipos de índice, este es el mismo que indexSelectivity multiplicado por
el número de filas del índice, pero podría ser más. (Ten en cuenta que el
tamaño del índice en páginas y filas está disponible en la estructura
path->indexinfo).
Estima el número de páginas de índice que se recuperarán durante el escaneo.
Esto podría ser simplemente indexSelectivity multiplicado por el tamaño del índice en páginas.
Calcula el costo de acceso al índice. Un estimador genérico podría hacer esto:
/*
* Nuestra suposición genérica es que las páginas de índice se leerán
* secuencialmente, por lo que cuestan seq_page_cost cada una, no random_page_cost.
* Además, cobramos por la evaluación de las indexquals en cada fila de índice.
* Se supone que todos los costos se pagan de forma incremental durante el escaneo.
*/
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;
Sin embargo, lo anterior no tiene en cuenta la amortización de las lecturas de índice a lo largo de escaneos de índice repetidos.
Estima la correlación del índice. Para un índice ordenado simple en un solo campo, esto se puede recuperar de pg_statistic. Si no se conoce la correlación, la estimación conservadora es cero (sin correlación).
Se pueden encontrar ejemplos de funciones de estimación de costos en
src/backend/utils/adt/selfuncs.c.