59.1. Funciones de soporte del método de muestreo #

La función manejadora TSM devuelve una estructura TsmRoutine asignada con palloc que contiene punteros a las funciones de soporte descritas a continuación. La mayoría de las funciones son obligatorias, pero algunas son opcionales y esos punteros pueden ser NULL.

void
SampleScanGetSampleSize (PlannerInfo *root,
                         RelOptInfo *baserel,
                         List *paramexprs,
                         BlockNumber *pages,
                         double *tuples);

Esta función se llama durante la planificación. Debe estimar el número de páginas de la relación que se leerán durante un escaneo de muestra, y el número de tuplas que se seleccionarán en el escaneo. (Por ejemplo, estos podrían determinarse estimando la fracción de muestreo y luego multiplicando los números de baserel->pages y baserel->tuples por ella, asegurándose de redondear los resultados a valores enteros). La lista paramexprs contiene la(s) expresión(es) que son parámetros de la cláusula TABLESAMPLE. Se recomienda usar estimate_expression_value() para intentar reducir estas expresiones a constantes, si sus valores son necesarios para fines de estimación; pero la función debe proporcionar estimaciones de tamaño incluso si no se pueden reducir, y no debe fallar incluso si los valores parecen inválidos (recuerda que solo son estimaciones de lo que serán los valores en tiempo de ejecución). Los parámetros pages and tuples son salidas.

void
InitSampleScan (SampleScanState *node,
                int eflags);

Inicializa para la ejecución de un nodo de plan SampleScan. Esto se llama durante el inicio del ejecutor. Debe realizar cualquier inicialización necesaria antes de que pueda comenzar el procesamiento. El nodo SampleScanState ya ha sido creado, pero su campo tsm_state es NULL. La función InitSampleScan puede asignar con palloc cualquier dato de estado interno que necesite el método de muestreo y almacenar un puntero a él en node->tsm_state. La información sobre la tabla a escanear es accesible a través de otros campos del nodo SampleScanState (pero ten en cuenta que el descriptor de escaneo node->ss.ss_currentScanDesc aún no está configurado). eflags contiene bits de bandera que describen el modo de operación del ejecutor para este nodo de plan.

Cuando (eflags & EXEC_FLAG_EXPLAIN_ONLY) es true, el escaneo no se realizará realmente, por lo que esta función solo debe hacer lo mínimo requerido para que el estado del nodo sea válido para EXPLAIN y EndSampleScan.

Esta función se puede omitir (establecer el puntero en NULL), en cuyo caso BeginSampleScan debe realizar toda la inicialización requerida por el método de muestreo.

void
BeginSampleScan (SampleScanState *node,
                 Datum *params,
                 int nparams,
                 uint32 seed);

Comienza la ejecución de un escaneo de muestra. Esto se llama justo antes del primer intento de obtener una tupla, y puede llamarse nuevamente si el escaneo necesita ser reiniciado. La información sobre la tabla a escanear es accesible a través de los campos del nodo SampleScanState (pero ten en cuenta que el descriptor de escaneo node->ss.ss_currentScanDesc aún no está configurado). El arreglo params, de longitud nparams, contiene los valores de los parámetros suministrados en la cláusula TABLESAMPLE. Estos tendrán la cantidad y los tipos especificados en la lista parameterTypes del método de muestreo, y se ha verificado que no sean nulos. seed contiene una semilla para usar con cualquier número aleatorio generado dentro del método de muestreo; es una firma hash derivada del valor de REPEATABLE si se proporcionó uno, o el resultado de random() en caso contrario.

Esta función puede ajustar los campos node->use_bulkread y node->use_pagemode. Si node->use_bulkread es true, que lo es por defecto, el escaneo utilizará una estrategia de acceso al búfer que fomenta la reutilización de los búferes después de su uso. Podría ser razonable establecer esto en false si el escaneo visitará solo una pequeña fracción de las páginas de la tabla. Si node->use_pagemode es true, que lo es por defecto, el escaneo realizará la verificación de visibilidad en una sola pasada para todas las tuplas en cada página visitada. Podría ser razonable establecer esto en false si el escaneo seleccionará solo una pequeña fracción de las tuplas en cada página visitada. Eso resultará en que se realicen menos verificaciones de visibilidad de tuplas, aunque cada una será más costosa porque requerirá más bloqueos.

Si el método de muestreo está marcado como repeatable_across_scans, debe ser capaz de seleccionar el mismo conjunto de tuplas durante un reescaneo como lo hizo originalmente, es decir, una nueva llamada de BeginSampleScan debe conducir a la selección de las mismas tuplas que antes (si los parámetros de TABLESAMPLE y la semilla no cambian).

BlockNumber
NextSampleBlock (SampleScanState *node, BlockNumber nblocks);

Devuelve el número de bloque de la siguiente página que se va a escanear, o InvalidBlockNumber si no quedan páginas por escanear.

Esta función se puede omitir (establecer el puntero en NULL), en cuyo caso el código central realizará un escaneo secuencial de toda la relación. Dicho escaneo puede utilizar un escaneo sincronizado, por lo que el método de muestreo no puede asumir que las páginas de la relación se visitan en el mismo orden en cada escaneo.

OffsetNumber
NextSampleTuple (SampleScanState *node,
                 BlockNumber blockno,
                 OffsetNumber maxoffset);

Devuelve el número de desplazamiento (offset) de la siguiente tupla a muestrear en la página especificada, o InvalidOffsetNumber si no quedan tuplas por muestrear. maxoffset es el número de desplazamiento más grande en uso en la página.

Note

A NextSampleTuple no se le indica explícitamente cuáles de los números de desplazamiento en el rango 1 .. maxoffset contienen realmente tuplas válidas. Esto normalmente no es un problema, ya que el código central ignora las solicitudes para muestrear tuplas faltantes o invisibles; eso no debería dar lugar a ningún sesgo en la muestra. Sin embargo, si es necesario, la función puede usar node->donetuples para examinar cuántas de las tuplas que devolvió eran válidas y visibles.

Note

NextSampleTuple no debe asumir que blockno is the same page number returned by the most recent NextSampleBlock call. It was returned by some previous NextSampleBlock call, but the core code is allowed to call NextSampleBlock in advance of actually scanning pages, so as to support prefetching. It is OK to assume that once sampling of a given page begins, successive NextSampleTuple calls all refer to the same page until InvalidOffsetNumber is returned.

void
EndSampleScan (SampleScanState *node);

Finaliza el escaneo y libera los recursos. Normalmente no es importante liberar la memoria asignada con palloc, pero cualquier recurso visible externamente debe ser limpiado. Esta función se puede omitir (establecer el puntero en NULL) en el caso común de que no existan tales recursos.