PG12: una docena de parches de Postgres Professional

Es agradable ver nombres familiares en la lista de Agradecimientos de la versión oficial de PostgreSQL 12. Decidimos reunir las innovaciones y algunas correcciones de errores en las que nuestros desarrolladores trabajaron.

1. Soporte de JSONPath


(En las Notas de la versión, esto suena como Agregar soporte para el lenguaje de ruta SQL / JSON (Nikita Glukhov, Teodor Sigaev, Alexander Korotkov, Oleg Bartunov, Liudmila Mantrova)

Este parche en sí, las características de JSONPath y el historial del problema se discutieron en detalle en un artículo separado aquí en el centro JSONPath es un logro importante de Postgres Professional y una de las principales innovaciones de PostgreSQL 12 en general.

En 2014, A. Korotkov, O. Bartunov y F. Sigaev desarrollaron la extensión jsquery , que se incluyó como resultado en Postgres Pro Standard 9.5 (y en versiones posteriores de Standard y Enterprise). Proporciona características adicionales muy amplias para trabajar con json (b).

Cuando apareció el SQL estándar: 2016, resultó que su semántica no es tan diferente de la nuestra en la extensión jsquery. Es posible que los autores del estándar incluso hayan mirado a jsquery, inventando JSONPath. Nuestro equipo tuvo que implementar un poco diferente de lo que ya teníamos y, por supuesto, muchas cosas nuevas también.

Aunque todavía no se ha confirmado un parche especial con funciones, el parche JSONPath ya tiene funciones clave para trabajar con JSON (B), por ejemplo:

jsonb_path_query('{"a": [1,2,3,4,5]}', '$.a[*] ? (@ > 2)')  3, 4, 5 jsonb_path_query('{"a": [1,2,3,4,5]}', '$.a[*] ? (@ > 5)')  0  

Además, algunas funciones que ya habían funcionado con JSON anteriormente fueron optimizadas . Esto fue hecho con éxito por Nikita Glukhov.

Por ejemplo, el operador #>> , correspondiente a las funciones jsonb_each_text() y jsonb_array_elements_text() , solía convertir rápidamente JsonbValue a texto, pero funcionaba lentamente con otros tipos. Ahora todo está funcionando rápido.

2. Soporte para búsqueda rápida de vecinos más cercanos en los índices SP-GiST (KNN)


(Agregue soporte para búsquedas de vecinos más cercanos (KNN) de índices SP-GiST. Nikita Glukhov, Alexander Korotkov, Vlad Sterzhanov)

Nikita Glukhov y Alexander Korotkov de nuestra compañía continuaron el trabajo iniciado por Vlad Sterzhanov de Minsk (también conocido como Quadrocube). Postgres fue el primer DBMS en buscar a sus vecinos más cercanos, anteriormente Oracle y MS, y de una manera mucho más directa y conveniente, y este fue el mérito de Oleg Bartunov y su equipo. La idea de esta búsqueda está en el algoritmo original de recorrido del árbol, que en la mayoría de los casos proporciona una gran ganancia. La búsqueda de vecinos más cercanos se usa mucho donde, pero en SIG es especialmente común.

Vlad hizo un parche de búsqueda KNN para trabajar con índices espaciales SP-GiST para árboles cuádruples, cuando el plano se divide en cuadrados de un tamaño fijo, y para árboles KD, es decir, árboles k-dimensionales.

Alexander Korotkov, mentor de Vlad GSoC (Google Summer of Code), continuó el desarrollo con un colega del profesional de Postgres Nikita Glukhov. La funcionalidad se enriqueció seriamente: se mejoró el almacenamiento en caché interno de datos al atravesar el árbol, se agregaron clases de operador para círculos y polígonos con orden por distancia.

Para usar el algoritmo de búsqueda de vecino más cercano, simplemente escriba ORDER BY [, ] , y luego el optimizador conectará automáticamente este algoritmo. Por ejemplo

 SELECT * FROM polygons ORDER BY poly <-> point '(0,0)'; 

Los parches de Nikita Glukhov se pueden ver en el github .

3. Optimización de bloqueos para acelerar la inserción en índices B-Tree


(En las Notas de la versión, esto es Mejorar la velocidad de las inserciones de índice btree al reducir la sobrecarga de bloqueo. Alexander Korotkov)

Alexander Korotkov, arquitecto jefe de sistemas en Postgres Professional, logró crear un algoritmo de bloqueo más razonable al insertar en índices de árbol B. La ganancia después de aplicar este parche es notable en los casos en que la inserción se produce más o menos "en una fila". Las mediciones en un servidor de 72 núcleos mostraron que en este caso la ganancia alcanza el 50%. Con una inserción caótica, la ganancia no es tan notable.

4. WAL económico


(Reduzca la sobrecarga de escritura WAL de la creación de índices GiST, GIN y SP-GiST. Anastasia Lubennikova, Andrey V. Lepikhov)

Esta serie de parches reduce el tráfico WAL generado al crear índices GiST, GIN y SP-GiST. Ahora puede registrar páginas de dichos índices solo una vez, al final, cuando el índice ya está construido. Y en caso de un error al crear el índice de entradas en el WAL, los intentos fallidos no aparecerán en absoluto. Anteriormente, esto solo era posible al crear un árbol B y RUM. Los parches usan el mecanismo genérico WAL .

Se xlog scripts para verificar el tamaño de xlog . Las pruebas en la base de datos IMDB (formato JSON), en las que los registros 4M + que ocupan 4GB, mostraron:

 CREATE INDEX ON imdb USING gin(jb jsonb_path_ops); 

la forma anterior ejecutó 205 segundos, WAL 3.2 GB, y el nuevo algoritmo dio 133 segundos, y WAL 0.4 GB.

5. Optimización del escaneo de solo índice en el caso de muchas columnas.


(Permita que los escaneos de solo índice sean más eficientes en índices con muchas columnas. Konstantin Knizhnik)

Al analizar el funcionamiento de la base de datos de uno de los clientes de nuestra empresa, se descubrió que la misma consulta se ejecuta en algunos casos durante más tiempo en un 25% con exploración de índice solamente que con exploración de índice (enable_indexonlyscan = off).
Esto sucedió cuando SELECT se realizó en muchos campos, que eran principalmente del tipo bytea , y su desplazamiento no se almacenó en caché, ya que dichos campos no tienen un desplazamiento fijo (ver también el informe de Nikolai Shaplov "What's Inside It" ). Para desempaquetar el atributo k-th, debe desempaquetar el k-1 anterior. Desempacar un registro por un atributo requiere un tiempo O (N * N), donde N es el número de campos. Este 25% ya sucedió en 10 campos.

Konstantin Knizhnik utilizó el algoritmo que se utiliza cuando se trabaja con hip: al acceder al atributo k-ésimo, se toman y recuerdan los k-1 anteriores, el tiempo crece linealmente con el número de campos. Después de aplicar el parche, el tiempo de ejecución con exploración de índice y exploración de índice solo es prácticamente el mismo.

6. Controle la descarga de segmentos WAL al disco


(Agregue un evento de espera para fsync de segmentos WAL. Konstantin Knizhnik)

El kernel PostgreSQL supervisa la escritura en WAL, pero no supervisa el vaciado de los segmentos WAL de la memoria al disco, es decir, fsync . K. Knizhnik realizó un parche que crea un nuevo tipo de evento, ahora se llama WALSync (el nombre interno de la variable es WAIT_EVENT_WAL_SYNC). Puede verlo en la etiqueta del evento PG con la explicación "Esperando a que el archivo WAL sea volcado a un almacenamiento confiable". Este problema se discutió en la lista de correo de los hackers .

Por lo general, se desconoce cuánto tarda el restablecimiento: PostgreSQL estándar no sabe cómo agregar tales estadísticas. Pero hay una extensión pg_wait_sampling escrita en Postgres Professional. Puede hablar sobre los eventos en los que Postgres pasa el tiempo. Ahora que se agregó el evento, puede seguir fsync .

7. Soporte para nuevos idiomas en diccionarios stemmer


(Actualice los diccionarios de Snowball stemmer con soporte para nuevos idiomas. Arthur Zakirov)

¡Dado que las conferencias de Postgres se llevan a cabo en Nepal, es mucho más natural agregar nepalés a la base de datos! Esto fue hecho. Gracias a los esfuerzos de Arthur Zakirov, ahora puedes usar el diccionario de nepalés en Snowball .

8. Las funciones to_timestamp () / to_date () se han vuelto más tolerantes a los datos


(Ajuste las funciones to_timestamp () / to_date () para ser más indulgente con los desajustes de plantillas, Artur Zakirov, Alexander Korotkov, Liudmila Mantrova)

La función to_timestamp() no funcionaba si la cadena de formato se procesaba con espacios adicionales. La discusión del error en to_timestamp() resultó en una larga discusión sobre qué comportamiento de las funciones to_timestamp() y, al mismo tiempo, to_date() considerarse correctas. Para beneficio de todos, ambas funciones se han vuelto más tolerantes a los espacios adicionales en la línea de formato y la línea de entrada.

9. Los registros se pueden rotar a través de pg_ctl


(Permitir el control de la rotación del archivo de registro a través de pg_ctl. Kyotaro Horiguchi, Alexander Kuzmenkov, Alexander Korotkov)

En otras palabras, la utilidad pg_ctl ha adquirido una nueva opción:

 pg_ctl logrotate [-D _] [-s] 

Cuando se ejecuta este comando, el servidor cambia a un nuevo archivo de registro o vuelve a abrir el existente, según la configuración de registro . Esto puede ser necesario en situaciones de emergencia, especialmente cuando grandes archivos de registro de rápido crecimiento necesitan, por ejemplo, ser transferidos para diagnóstico.

10. La capacidad de crear nuevos tipos de tablas (almacenamiento conectable)


(Agregue el comando CREATE ACCESS METHOD para crear nuevos tipos de tabla. Andres Freund, Haribabu Kommi, Álvaro Herrera, Alexander Korotkov, Dmitry Dolgov)

Este importante parche es una parte esencial de la infraestructura de API de almacenamiento conectable, de ahí la composición internacional de los desarrolladores de parches. El comando CREATE ACCESS METHOD se ha estado ejecutando en Postgres desde la versión 9.6. Pero hasta el día 12, solo puede crear métodos de acceso al índice. Aquí está la documentación para la 11ª versión :

 CREATE ACCESS METHOD  TYPE __ HANDLER _ < ... > __       .      INDEX. 

Y en la documentación para el 12 ya leída : actualmente solo se admiten TABLE e INDEX. Por cierto, en el undécimo comando CREATE ACCESS METHOD fue proporcionado por la extensión Postgres Pro, y en el duodécimo ya PostgreSQL.

La ejecución de la operación depende del tipo de método de acceso; si es un tipo TABLE, entonces table_am_handler lo table_am_handler , y si es un tipo INDEX, entonces index_am_handler (anteriormente: para los métodos de acceso de tipo INDEX, debería ser index_am_handler ). Un capítulo entero ha aparecido en la documentación sobre métodos de tabla.

Al crear una tabla, ahora puede especificar su tipo:

 CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXISTS ] _ ( [ < ... > [ USING  ] 

el método es de tipo TABLE: esta es una referencia al almacenamiento conectable. Ahora es un heap por defecto, y antes que el otro, de hecho, no lo era. Sobre las clases de operadores aquí

default_table_access_method (string)

Este parámetro establece el método de acceso a la tabla predeterminado que se utilizará al crear tablas o vistas materializadas si el método de acceso no se especifica explícitamente en el comando CREAR, o al ejecutar el comando SELECCIONAR ... INTO, en el que el método de acceso no se puede establecer explícitamente. El valor predeterminado es el heap . La gran discusión en los piratas informáticos ayuda a sacar los detalles.

Hasta este momento, hablamos de innovaciones. Pero las correcciones de errores también eliminan los recursos del tiempo de los programadores. Los principales son:

11. Error: un error en una de las estructuras.


Extra quote_all_identifiers en _dumpOptions. Arthur Zakirov)

En general, nada especial, se encontró un error en una de las estructuras que usa pg_dump ; el compilador lo pasó por alto. Pero Bruce Momjyan mismo elogió el hallazgo.

Otros problemas con DumpOptions se pueden encontrar aquí .

12. Error en la replicación:


(xlogreader: no lea un bloque de archivo dos veces. Arthur Zakirov)

Otro empleado de nuestra empresa, el desarrollador de pg_probackup Grigory Smolkin, descubrió que una de nuestras utilidades se ralentiza cuando xlogreader lee los archivos zlib. Resultó que a veces lee los bloques de archivos WAL dos veces.

Si los archivos se leen de manera inconsistente, el rendimiento es bajo. La lectura repetida del bloque siempre es inconsistente, ya que debe volver a la posición pasada llamando a la función gzseek() . Ahora no se vuelve a leer innecesariamente.

PD: no voy a desglosar: una docena de parches (estrictamente hablando una docena de series de parches) no son solo una coincidencia accidental con el número de versión de Postgres. La lista bien podría ser menos de una docena o más de una docena. Pensé que sería más hermoso, y la belleza es en parte el motor de la programación, sin mencionar otras áreas de la actividad humana.

Source: https://habr.com/ru/post/472072/


All Articles