Novedades de Greenplum 7. Parte 2 / Sudo Null IT News

En la última parte de la revisión de cambios e innovaciones en Greenplum 7, analizamos la migración del motor de tablas Append Optimized para usar la interfaz de métodos de acceso a tablas, la optimización de la adición de columnas a las tablas, así como los cambios relacionados con el soporte de índices. .

Hoy hablaremos sobre otro nuevo tipo de índice para Greenplum y más.

Índices BRIN

Todas las innovaciones en términos de índices mencionadas anteriormente no parecen imprescindibles para la carga de trabajo analítico. ¿Con qué frecuencia hay que extraer valores únicos o, especialmente, únicos de una tabla que contiene millones y miles de millones de registros? Eso es todo. Estas mejoras probablemente serán útiles para tablas auxiliares o libros de referencia.

Un escenario mucho más común es seleccionar un subconjunto de filas que cumplan los criterios deseados para uniones, agregaciones, etc. posteriores. Y aquí se demandan técnicas que le permitan limitar el rango de búsqueda y excluir aquellos bloques de datos que obviamente no son necesarios: omisión de datos, poda de metadatos. Anteriormente, a estos efectos el usuario tenía acceso a:

  • Partición de mesas. Los datos se dividen físicamente en diferentes tablas y, como resultado, archivos. Es posible escanear solo aquellas particiones que puedan contener los datos deseados; es posible mantener, realizar copias de seguridad y recargar la tabla en partes. El costo es la rigidez de la estructura, una mayor carga en el directorio de la base de datos y mayores exigencias para los planificadores, quienes deben conocer la topología de la tabla para poder elaborar un plan eficaz para ella.

  • índices de mapa de bits, que serán buenos para columnas con baja cardinalidad (de lo contrario, el tamaño que ocupen en el disco cubrirá todas sus ventajas). Le permiten combinar varios índices en diferentes columnas en un plan de consulta mediante operaciones entre máscaras de bits.

  • Índices btree, que, a diferencia del mapa de bits, también pueden funcionar en columnas con un alto porcentaje de valores únicos, pero requerirán una importante sobrecarga de mantenimiento y uso.

A partir de Postgres 9.5 y Greenplum 7, otra opción estuvo disponible para los usuarios: los índices brin (Block Range Index). La esencia de este tipo de índice es que todo el espacio de direcciones de la tabla se divide en rangos de tamaño fijo. Para tablas de montón, este es el número de páginas, configurable para cada índice de tabla, cuyos números constituyen los bits más significativos en el identificador de versión de fila. Para cada rango, el índice almacena metainformación que describe los valores almacenados en él. En la versión más sencilla, para tipos ordenados, los valores mínimo y máximo. En otros más complejos, abarcando valores, por ejemplo, un área que incluye las coordenadas de todos los puntos almacenados en el bloque. Y, dado que solo almacenamos unos pocos valores por rango, dicho índice es mucho más compacto que un árbol b.

Al acceder a dicho índice, podemos obtener los identificadores de todos los bloques que potencialmente podrían almacenar los valores que solicitamos y gastar recursos solo en escanearlos. Obviamente, será necesario volver a verificar cada valor extraído, ya que el intervalo solicitado no cubre necesariamente todo el rango de bloques seleccionados para escanear. Y cuanto más estrecha y precisa sea la descripción de cada rango de bloques del mismo tamaño, más eficiente será el escaneo por índice, ya que se seleccionarán menos bloques durante el escaneo y contendrán menos valores “innecesarios”.

Por lo tanto, buenos candidatos para usar este tipo de índice serán las columnas cuya naturaleza de carga de datos en la tabla se correlacione con consultas posteriores. Los datos se descargarán en orden cronológico o diariamente y luego se solicitarán durante períodos de tiempo más largos (semana, mes). Genial. A menudo, como guía, se propone utilizar columnas para las cuales, según las estadísticas, existe una correlación directa o inversa entre el valor y su ubicación en la tabla. Puede forzar una correlación reescribiendo la tabla en el orden deseado usando el comando CLUSTER en presencia de un índice, y utilizando ALTER TABLE REPACK BY COLUMNSimplementado para Greenplum 7 (8ee44e8) – incluso en su ausencia. Este último requería una función adicional más en la interfaz de los métodos de tabla: table_relation_copy_for_repack.

Veamos cómo se realiza una búsqueda utilizando el índice brin (ver la implementación de la función amgetbitmap método de acceso al índice – bringetbitmap) para comprender qué dificultades surgieron al adaptar el índice para las tablas AO:

  1. Solicitamos el número de páginas de la tabla.

  2. La descripción en el índice no se almacena para cada página, sino para su rango. Por lo tanto, recorreremos cada rango de páginas de la tabla y usaremos el índice para determinar si puede almacenar algo que nos interese.

  3. Las primeras páginas del índice Brin siempre contienen el llamado mapa de rango inverso (revmap). Siempre ocupa un rango de páginas contiguas y, por simplicidad, podemos considerarlo como una serie de punteros que nos permiten obtener una descripción para el rango de páginas deseado.

  4. Si no se ha encontrado una descripción para un rango de bloques (por ejemplo, si aún no se ha resumido la información sobre el rango), todas sus páginas se marcarán para escanear incondicionalmente.

  5. En caso contrario, se llamará a una función de soporte, que interpreta la información generalizada y decide sobre la conveniencia de escanear un rango determinado de bloques.

  6. Como resultado, se creará un mapa de bits que marcará todas las páginas que potencialmente contengan las filas solicitadas.

Ahora veamos detenidamente el paso 3 nuevamente y recordemos qué es un identificador de versión de fila para una tabla AO. Permítanme recordarles que no tenemos páginas de tamaño fijo y, en general, el número de línea no refleja de ninguna manera el número de página física. Pero los 7 bits superiores almacenan el número del archivo de segmento, que contiene una versión específica de la línea. Por lo tanto, si al menos una línea está almacenada en el archivo de segmento 127 más alto disponible, necesitaremos un mapa de rango inverso que nos permita abordar al menos 0xFE000000 páginas. Una sola página de índice brin de 32 KB en una compilación de Greenplum se adapta a aproximadamente 5454 punteros de forma predeterminada. Así, el mapa ocupará más de 781 mil páginas o 23 Gb+. A modo de comparación, en una compilación de Postgres con páginas de 8 KB, este número de página correspondería a una tabla que ocupa más de 32 TB de espacio en disco. En el caso de una tabla AO, dicho identificador puede ser una sola fila en toda la tabla.

Por esta razón, los índices brin han sufrido modificaciones significativas para soportar las tablas AO (63d916b). Toda la gama de identificadores de versión de fila disponibles se puede dividir en secuencias mediante el método de acceso a la tabla (BlockSequences) sin lagunas tan significativas dentro de cada uno de ellos. Sí, para ello ha aparecido otra función en la interfaz de métodos de acceso: relation_get_block_sequences. Para tablas de montón, devuelve exactamente una secuencia desde la primera hasta la última página. Para Append Optimized, habrá secuencias de acuerdo con la cantidad de archivos de segmento. Para cada archivo de segmento, la primera página será la página cuyo número consta del número del archivo de segmento (7 bits altos) y 25 bits llenos de ceros. La última página será la correspondiente al valor actual (!) del generador de números de versión de línea para este archivo de segmento (FastSequence). Dado que el valor del generador no se restablece durante la vida útil de la tabla, las actualizaciones intensivas seguidas de la recolección de basura aún darán como resultado que se almacene información de página inexistente en el mapa de rango inverso. Las páginas en sí serán puramente lógicas y cubrirán rangos de identificadores de versión de 32k filas, lo que corresponde a los dos bytes bajos. ctid. Dicha página lógica será la unidad mínima para la cual se almacena información generalizada en el índice. Esto significa que la cantidad mínima de información leída del disco dependerá del ancho de fila de una tabla en particular y, en el caso del almacenamiento en columnas, de las columnas requeridas por la consulta, a diferencia de una tabla de montón, para la cual el tamaño de la página es fijado. Es importante tener esto en cuenta al elegir un valor. pages_per_range durante la creación del índice.

Así, para las tablas AO, el escaneo por índice brin se realizará de la siguiente manera:

  1. Para cada archivo de tabla de segmentos, formamos una secuencia de páginas lógicas (Block Sequence).

  2. Para cada secuencia de páginas, extraemos de la metapágina el número de la primera página del mapa de rango inverso.

  3. Para cada rango de páginas, comenzando con el rango correspondiente al número de archivo del segmento:

  4. Obtenemos el número de página del mapa de rango inverso en la cadena descartando los bits más significativos correspondientes al número de archivo del segmento, dividiéndolos por el número máximo de rangos por página del mapa.

  5. Pasamos a la página siguiente del mapa de rango inverso si el número de página actual es menor que el deseado.

  6. Obtenemos el número del puntero de línea en la página del mapa como el resto de dividir el número de página por el número máximo de rangos que se pueden almacenar en él.

  7. Usando el desplazamiento resultante, obtenemos el identificador de registro (página + número de registro), que describe el rango actual.

  8. Recupera la página y el registro que contiene la descripción del rango.

  9. Utilizando la función de soporte, verificamos si la información del rango generalizado corresponde a la condición solicitada. Si el rango puede contener valores de interés para el usuario o falta información resumida (por ejemplo, no se ha recopilado), cada una de sus páginas lógicas se marca en el mapa de bits.

  10. Una vez que se completa la construcción del mapa de bits (operador Bitmap Index Scan), extraemos secuencialmente versiones de filas con identificadores que pertenecen a páginas lógicas (Bitmap Heap Scan) y vuelva a verificar la condición especificada por el usuario para ellos. Mapa de bloques (Block Directory) nos ayuda a obtener el desplazamiento de los bloques físicos en los archivos correspondientes al inicio de cada página lógica. De este modo, reducimos la cantidad de datos que deben leerse del disco.

Como ejemplo, considere escanear una tabla de tres columnas con índices btree y brin en la columna b un tipo entero que recuperará un rango que contiene aproximadamente el 0,7% de los registros. A continuación se muestran los planes de consulta y el tiempo que lleva completarlos.

ORCA para Greenplum 7.1 no alcanza el costo del escaneo de índice y utiliza de manera predeterminada el escaneo secuencial:

Cuando, para obtener el mismo resultado, el segmento que almacenó la mayoría de las filas buscadas solo necesita escanear dos páginas lógicas (Heap Blocks) utilizando el índice brin. Estos bloques contendrán solo 23430 líneas buscadas; las 42105 restantes se filtrarán después de volver a verificar la condición.

Se puede lograr un resultado similar utilizando un índice btree. La diferencia es que este método de acceso y la cantidad de valores recuperados le permiten crear un mapa de bits preciso (hasta el identificador de versión de fila) y evitar verificar la condición dos veces. Pero el precio de esto será el tamaño de los índices, que serán dos órdenes de magnitud mayores.

Operaciones paralelas dentro de un segmento

Postgres 9.6 introdujo la capacidad de paralelizar muchas operaciones dentro de una consulta. Sin embargo, los desarrolladores de Greenplum no encontraron una manera rápida de combinar la paralelización de consultas dentro de un clúster y dentro de un segmento de clúster específico. Y fuera de peligro prohibido paralelización de consultas dentro de un segmento:

Para tener una idea de los posibles desafíos de implementación, basta con mirar el plan paralelo de Postgres:

Luego intente imaginar cómo sería una versión distribuida de dicho plan:

Dónde X — el número de procesos de trabajo, no segmentos en el clúster. Reemplazo Gather en Gather Motion Parece orgánico. CON Redistribute Motion más difícil. Cada uno de los procesos de trabajo en un segmento debe recibir solo filas correspondientes a un segmento determinado, pero distribuidas uniformemente entre ellas.

Además, la cuestión de la paralelización del análisis de tablas optimizadas para anexos sigue abierta. El enfoque de montón existente se basa en un tamaño fijo de páginas, cuyo número se conoce al inicio del escaneo.

Por otro lado, esto podría simplificar significativamente la gestión de clústeres, así como la distribución de recursos dentro de un host, incluso mediante la regulación del número de procesos de trabajo. Siempre que una instancia de Postgres pueda utilizar los recursos de una máquina física.

Ampliando las capacidades de las tablas extranjeras

Postgres proporciona a los desarrolladores una extensión API de tabla externa que les permite recuperar o modificar datos de fuentes arbitrarias. Una fuente tan arbitraria puede ser un archivo, almacenamiento s3, Postgres, Kafka o incluso otro clúster de Greenplum.

El proceso de recuperación de filas del almacenamiento externo está oculto detrás de un nodo del plan. Foreign Scan. Imaginemos que tenemos dos tablas en Postgres externo, cuyo resultado queremos usar en Greenplum:

En Postgres 9.4 y Greenplum 6, las capacidades de FDW se limitaban a reenviar predicados a un sistema remoto. La propia conexión y su posterior procesamiento se realizarán en el iniciador de la solicitud (en este caso, en el coordinador).

Sin embargo, en el mundo de Postgres, la vida siguió como siempre. Postgres 9.6 introdujo la capacidad de reenviar conexiones, ordenar y UPDATE/DELETE-operaciones. Postgres 10 agregó soporte para agregados. Postgres 12 amplió el soporte para clasificación y también implementó soporte para reenvío LIMIT. Recibidos estos cambios, podremos ver el siguiente plan de consulta, en el que el resultado será evaluado completamente en el sistema remoto:

Ahora será posible utilizar un arsenal de estas capacidades en conectores para varios sistemas. Además, para utilizar estas capacidades, deberá modificar el segundo programador disponible en la distribución de Greenplum: ORCA. En las versiones actuales, ORCA construye un plan similar al que pudimos ver en Greenplum 6.

Capacidades de monitoreo del flujo de trabajo de la base de datos

La solicitud tarda mucho en completarse. EXPLAIN ANALYZE No puedo esperar. Todo lo que las herramientas estándar de Greenplum 6 podían proporcionarnos era una columna wait_reason representación pg_stat_activity con significados cerrar, replicación o reagrupar. Poco. Tuve que recorrer todo el cluster buscando un cuello de botella, conectando un rastreador, un depurador, etc. En Postgres 9.6 esta situación comenzó a cambiar (53be0b1), luego se desarrolló en Postgres 10 (6f3bd98 y 249cf07). Ahora el usuario dispone de una amplia lista de motivos de la espera del proceso actual para su análisis.

En este ejemplo, podemos ver que el coordinador envió una solicitud de segmentos y está esperando que se complete. Dos de los tres segmentos estaban bloqueados en E/S en el momento de la solicitud: estaban esperando que las extensiones de archivo de la tabla cargaran nuevos datos. El tercero espera a que una réplica síncrona (espejo) lo alcance para continuar con la inserción. Actualmente no hay una lista completa de expectativas en la documentación de Greenplum que pueda utilizar; documentación Postgres o estudie las fuentes de expectativas específicas de Greenplum.

Especial atención merece la nueva presentación. gp_stat_activity para recopilar información de todo el clúster; anteriormente tenía que escribir un contenedor usted mismo.

Además, con los parches de Postgres 10, la supervisión de los procesos en segundo plano del sistema está disponible. En el siguiente ejemplo, el proceso de escritura WAL se capturó esperando E/S mientras se vaciaba el contenido del búfer de registro de escritura anticipada en el disco:

Y eso no es todo

Analizamos el impacto de varios cambios más de Postgres en la funcionalidad de la nueva versión de Greenplum. En la tercera parte final, continuaremos analizando dichas mejoras y también hablaremos sobre cómo han cambiado las capacidades específicas de nuestra base de datos. Manténgase en contacto, gracias por su atención!

Agradezco a nuestros diseñadores @kawaii_anya y @nastoika_lera por su ayuda en la preparación de este artículo.

Publicaciones Similares

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *