sql >> Base de Datos >  >> RDS >> PostgreSQL

Ajuste de operaciones de entrada/salida (E/S) para PostgreSQL

PostgreSQL es una de las bases de datos de código abierto más populares del mundo y tiene implementaciones exitosas en varios entornos de misión crítica en varios dominios, utilizando aplicaciones OLTP de alto nivel en tiempo real que realizan millones y miles de millones de transacciones por día. La E/S de PostgreSQL es bastante confiable, estable y de alto rendimiento en prácticamente cualquier hardware, incluso en la nube.

Para garantizar que las bases de datos se desempeñen a la escala esperada con los tiempos de respuesta esperados, se necesita cierta ingeniería de rendimiento. Bueno, el logro de un buen rendimiento de la base de datos depende de varios factores. El rendimiento de la base de datos puede empeorar por varios motivos, como el dimensionamiento de la infraestructura, una estrategia de mantenimiento de base de datos ineficiente, un código SQL deficiente o procesos de base de datos mal configurados que no utilizan todos los recursos disponibles:CPU, memoria, ancho de banda de red y E/S de disco.

¿Qué puede hacer que se degrade el rendimiento de la base de datos?

  • Consultas mal escritas con malas uniones, lógica, etc. que consumen mucha CPU y memoria
  • Consultas que realizan escaneos completos de tablas en tablas grandes debido a una indexación incorrecta
  • Mal mantenimiento de la base de datos sin estadísticas adecuadas
  • Planificación de capacidad ineficiente que da como resultado una infraestructura dimensionada inadecuadamente
  • Diseño lógico y físico inadecuado
  • No hay agrupación de conexiones, lo que hace que las aplicaciones realicen una gran cantidad de conexiones de manera incontrolable

Esas son muchas áreas potenciales que pueden causar problemas de rendimiento. Una de las áreas importantes en las que me gustaría centrarme en este blog es cómo ajustar el rendimiento de E/S (entrada/salida) de PostgreSQL. Ajustar las operaciones de entrada/salida de PostgreSQL es esencial, especialmente en un entorno de muchas transacciones como OLTP o en un entorno de almacenamiento de datos con análisis de datos complejos en conjuntos de datos de gran tamaño.

La mayoría de las veces, los problemas de rendimiento de la base de datos se deben principalmente a una E/S alta. Esto significa que los procesos de la base de datos dedican más tiempo a escribir o leer desde el disco. Cualquier operación de datos en tiempo real está vinculada a E/S, es imperativo asegurarse de que la base de datos esté ajustada a E/S. En este blog, me centraré en los problemas comunes de E/S que pueden encontrar las bases de datos de PostgreSQL en entornos de producción en tiempo real.

Ajuste de E/S de PostgreSQL

Ajustar la E/S de PostgreSQL es imprescindible para construir una arquitectura de base de datos escalable y de alto rendimiento. Veamos varios factores que afectan el rendimiento de E/S:

  • Indización
  • Particionamiento
  • Puntos de control
  • VACÍO, ANALIZAR (con FACTOR DE RELLENO)
  • Otros problemas de E/S
  • E/S de PostgreSQL en la nube
  • Herramientas

Indización

La indexación es una de las técnicas de ajuste principales que desempeña un papel fundamental en la mejora del rendimiento de E/S de la base de datos. Esto se aplica realmente a cualquier base de datos. PostgreSQL admite varios tipos de índices que pueden acelerar en gran medida las operaciones de lectura, lo que brinda una escalabilidad mejorada para las aplicaciones. Si bien la creación de índices es bastante simple y directa, es esencial que los administradores de bases de datos y los desarrolladores conozcan qué tipo de índice elegir y en qué columnas. Este último se basa en varios factores, como la complejidad de la consulta, el tipo de datos, la cardinalidad de los datos, el volumen de escrituras, el tamaño de los datos, la arquitectura del disco, la infraestructura (nube pública, nube privada o local), etc.

Si bien la indexación puede mejorar drásticamente el rendimiento de lectura de consultas, también puede ralentizar las escrituras que llegan a las columnas indexadas. Veamos un ejemplo:

Impacto de los índices en las operaciones READ

Una tabla llamada emp con alrededor de 1 millón de filas.

Rendimiento de LECTURA sin índice

postgres=# select * from emp where eid=10;

 eid | ename    | peid | did  |    doj
-----+---------------+--------+------+------------
  10 | emp        |          |   1   | 2018-06-06
(1 row)
 
Time: 70.020 ms => took about 70+ milli-seconds to respond with on row

LEER rendimiento con un índice

Pongamos un índice en la columna eid y veamos la diferencia

postgres=# create index indx001 on emp ( eid );
CREATE INDEX

postgres=# select * from emp where eid=10;

 eid | ename  | peid | did |    doj
------+-------------+-------+------+------------
  10 | emp      |          |   1   | 2018-06-06
(1 row)
 
Time: 0.454 ms =>  0.4+ milli-seconds!!! thats a huge difference - isn’t it?

Por lo tanto, la indexación es importante.

Impacto de los índices en las operaciones de ESCRITURA

Los índices ralentizan el rendimiento de las escrituras. Si bien los índices tienen un impacto en todos los tipos de operaciones de escritura, veamos algunos análisis sobre el impacto de los índices en los INSERT

Insertar 1 millón de filas en una tabla sin índices

postgres=# do $$
postgres$# declare
postgres$# i integer;
postgres$# begin
postgres$# for i in 1..1000000 loop
postgres$# insert into emp values (i,'emp',null,1,current_date);
postgres$# end loop;
postgres$# end $$;
DO

Time: 4818.470 ms (00:04.818) => Takes about 4.8 seconds

Insertar el mismo millón de filas con un índice

Primero creemos un índice

postgres=# create index indx001 on emp ( eid );
CREATE INDEX

postgres=# do $$
postgres$# declare
postgres$# i integer;
postgres$# begin
postgres$# for i in 1..1000000 loop
postgres$# insert into emp values (i,'emp',null,1,current_date);
postgres$# end loop;
postgres$# end $$;
DO

Time: 7825.494 ms (00:07.825) =>  Takes about 7.8 seconds

Entonces, como podemos observar, el tiempo de INSERCIÓN aumentó en un 80% con solo un índice y puede tomar mucho más tiempo para terminar cuando hay múltiples índices. Puede empeorar aún más cuando hay índices basados ​​en funciones. ¡Eso es con lo que los DBA tienen que vivir! Los índices aumentarán el rendimiento de escritura. Sin embargo, hay formas de abordar este problema, que depende de la arquitectura del disco. Si el servidor de la base de datos utiliza varios sistemas de archivos de disco, los índices y las tablas se pueden colocar en varios espacios de tablas que se encuentran en varios sistemas de archivos de disco. De esta forma, se puede lograr un mejor rendimiento de E/S.

CONSEJOS para la gestión de índices

  • Comprender la necesidad de índices. La indexación inteligente es clave.
  • Evite crear múltiples índices, y definitivamente ningún índice innecesario, esto realmente puede degradar el rendimiento de escritura.
  • Supervise el uso de índices y elimine los índices no utilizados.
  • Cuando las columnas indexadas están sujetas a cambios de datos, los índices también se inflan. Por lo tanto, reorganice regularmente los índices.

Particionamiento

Una estrategia de particionamiento eficaz puede reducir en gran medida los problemas de rendimiento de E/S. Las tablas grandes se pueden particionar en función de la lógica empresarial. PostgreSQL admite la partición de tablas. Aunque no es totalmente compatible con todas las funciones en este momento, solo puede ayudar con algunos de los casos de uso en tiempo real. En PostgreSQL, las tablas secundarias particionadas son completamente independientes de la tabla maestra, lo que es un cuello de botella. Por ejemplo, las restricciones creadas en la tabla maestra no se pueden heredar automáticamente a las tablas secundarias.

Sin embargo, desde la perspectiva del equilibrio de E/S, la partición realmente puede ayudar. Todas las particiones secundarias se pueden dividir en múltiples tablespaces y sistemas de archivos de disco. Las consultas con un rango de fechas en la cláusula "dónde" que toca la tabla, divididas según el rango de fechas, pueden beneficiarse de la partición simplemente escaneando una o dos particiones en lugar de la tabla completa.

Puntos de control

Los puntos de control definen el estado consistente de la base de datos. Son críticos y es importante que los puntos de control se realicen con la suficiente regularidad para garantizar que los cambios en los datos se guarden de forma permanente en el disco y que la base de datos se mantenga en un estado constante todo el tiempo. Dicho esto, la configuración incorrecta de los puntos de control puede provocar problemas de rendimiento de E/S. Los administradores de bases de datos deben ser meticulosos en la configuración de los puntos de control para asegurarse de que no haya picos de E/S y esto también depende de qué tan buenos sean los discos y qué tan bien esté diseñado el diseño de los archivos de datos.

¿Qué hace el punto de control?

En términos simples, los puntos de control garantizarán:

  • Todos los datos confirmados se escriben en los archivos de datos del disco.
  • los archivos de obstrucción se actualizan con el estado de confirmación.
  • Los archivos de registro de transacciones en el directorio pg_xlog (ahora pg_wal) se reciclan.

Eso explica cuán intensivos son los puntos de control de E/S. Hay parámetros en postgresql.conf que se pueden configurar / ajustar para controlar el comportamiento del punto de control y esos parámetros son max_wal_size, min_wal_size, checkpoint_timeout y checkpoint_completion_target. Estos parámetros decidirán con qué frecuencia deben ocurrir los puntos de control y dentro de cuánto tiempo deben terminar los puntos de control.

¿Cómo entender qué configuración es mejor para los puntos de control? ¿Cómo afinarlos?

Estos son algunos consejos:

  • Evaluar la base de datos TPS. Evalúe el volumen total de transacciones que ocurren en la base de datos en un día hábil y también identifique a qué hora llega la mayor cantidad de transacciones a la base de datos.
  • Hable regularmente con los desarrolladores de aplicaciones y otros equipos técnicos para comprender las estadísticas de la tasa de transacciones de la base de datos, así como el crecimiento futuro de las transacciones.
  • Esto también se puede hacer desde el final de la base de datos:
    • Supervise la base de datos y evalúe la cantidad de transacciones que ocurren durante el día. Esto se puede hacer consultando tablas de pgcatalog como pg_stat_user_tables.

    • Evalúe la cantidad de archivos de almacenamiento wal generados por día

    • Supervise para comprender cómo funcionan los puntos de control habilitando el parámetro log_checkpoints

      2018-06-06 15:03:16.446 IST [2111] LOG:  checkpoint starting: xlog
      2018-06-06 15:03:22.734 IST [2111] LOG:  checkpoint complete: wrote 12112 buffers (73.9%); 0 WAL file(s) added, 0 removed, 25 recycled; write=6.058 s, sync=0.218 s, total=6.287 s; sync files=4, longest=0.178 s, average=0.054 s; distance=409706 kB, estimate=412479 kB
    • Comprenda si la configuración actual del punto de control es lo suficientemente buena para la base de datos. Configure el parámetro checkpoint_warning (configurado de forma predeterminada en 30 segundos) para ver las siguientes advertencias en los archivos de registro de postgres.

      2018-06-06 15:02:42.295 IST [2111] LOG:  checkpoints are occurring too frequently (11 seconds apart)
      2018-06-06 15:02:42.295 IST [2111] HINT:  Consider increasing the configuration parameter "max_wal_size".

¿Qué significa la advertencia anterior?

Los puntos de control generalmente ocurren cada vez que se llena max_wal_size (1 GB por defecto, lo que significa 64 archivos WAL) de archivos de registro o cuando se alcanza checkpoint_timeout (cada 5 minutos por defecto). La advertencia anterior significa que max_wal_size configurado no es adecuado y los puntos de control ocurren cada 11 segundos, lo que a su vez significa que 64 archivos WAL en el directorio PG_WAL se llenan en solo 11 segundos, lo cual es demasiado frecuente. En otras palabras, si hay transacciones menos frecuentes, los puntos de control ocurrirán cada 5 minutos. Entonces, como sugiere la sugerencia, aumente el parámetro max_wal_size a un valor más alto, el parámetro max_min_size se puede aumentar al mismo o menor que el anterior.

Otro parámetro crítico a considerar desde la perspectiva del rendimiento de E/S es checkpoint_completion_target, que está configurado de forma predeterminada en 0.5.

checkpoint_completion_target =0,5 x checkpoint_timeout =2,5 minutos

Eso significa que los puntos de control tienen 2,5 minutos para sincronizar los bloques sucios con el disco. ¿Son suficientes 2,5 minutos? Eso hay que evaluarlo. Si el número de bloques sucios que se van a escribir es muy alto, 2,5 minutos pueden parecer muy, muy agresivos y es entonces cuando se puede observar un pico de E/S. La configuración del parámetro finish_target debe realizarse en función de los valores max_wal_size y checkpoint_timeout. Si estos parámetros se elevan a un valor más alto, considere aumentar checkpoint_completion_target en consecuencia.

VACÍO, ANALIZAR (con FACTOR DE RELLENO)

VACUUM es una de las características más poderosas de PostgreSQL. Se puede usar para eliminar bloats (espacio fragmentado) dentro de tablas e índices, y lo generan las transacciones. La base de datos debe someterse a VACUUM regularmente para garantizar un mantenimiento saludable y un mejor rendimiento. Nuevamente, no VACÍAR la base de datos regularmente puede ocasionar serios problemas de rendimiento. ANALYZE debe realizarse junto con VACUUM (VACUUM ANALYZE) para garantizar estadísticas actualizadas para el planificador de consultas.

El ANÁLISIS DE VACÍO se puede realizar de dos formas:manual, automática o ambas. En un entorno de producción en tiempo real, generalmente son ambos. El VACÍO automático está habilitado por el parámetro "autovacuum" que está configurado por defecto en "on". Con el vacío automático habilitado, PostgreSQL automáticamente comienza a VACÍAR las tablas periódicamente. Las tablas candidatas que necesitan vaciado son seleccionadas por procesos de autovacuum basados ​​en varios umbrales establecidos por varios parámetros de autovacuum*, estos parámetros se pueden modificar/ajustar para garantizar que las tablas se borren periódicamente. Veamos algunos parámetros y su uso -

Parámetros de autovacío

autovacuum=on Este parámetro se usa para habilitar/deshabilitar el vacío automático. El valor predeterminado es "activado".
log_autovacuum_min_duration =-1 Registra la duración del proceso de autovacío. Esto es importante para comprender cuánto tiempo se ejecutó el proceso de vacío automático.
autovacuum_max_workers =3 Número de procesos de autovacío necesarios. Esto depende de cuán agresivas sean las transacciones de la base de datos y cuántas CPU pueda ofrecer para los procesos de vacío automático.
autovacuum_naptime =1 min Tiempo de descanso del autovacío entre ejecuciones de autovacío.

Parámetros que definen el umbral para el inicio del proceso Autovacuum

Los trabajos de vacío automático se inician cuando se alcanza un cierto umbral. A continuación se muestran los parámetros que se pueden usar para establecer un cierto umbral, en función del cual se iniciará el proceso de autovacío.

autovacuum_vacuum_threshold =50 La tabla se vaciará cuando se actualicen o eliminen un mínimo de 50 filas en una tabla.
autovacuum_analyze_threshold =50 La tabla se analizará cuando se actualicen o eliminen un mínimo de 50 filas en una tabla.
autovacuum_vacuum_scale_factor =0.2 La tabla se vaciará cuando se actualice/elimine un mínimo del 20 % de las filas en una tabla.
autovacuum_analyze_scale_factor =0.1 La tabla se vaciará cuando se actualice/elimine un mínimo del 10 % de las filas en una tabla.

Los parámetros por encima del umbral se pueden modificar según el comportamiento de la base de datos. Los administradores de bases de datos deberán analizar e identificar las tablas calientes y asegurarse de que esas tablas se vacíen con la mayor frecuencia posible para garantizar un buen rendimiento. Llegar a un cierto valor para estos parámetros podría ser un desafío en un entorno de muchas transacciones, en el que los datos cambian cada segundo. Muchas veces me di cuenta de que los procesos de vacío automático tardan bastante en completarse, lo que termina consumiendo demasiados recursos en los sistemas de producción.

Sugeriría no depender completamente del proceso de vacío automático, la mejor manera es programar un trabajo de ANÁLISIS DE VACÍO nocturno para reducir la carga del vacío automático. Para empezar, considere VACÍAR manualmente las mesas grandes con una alta tasa de transacciones.

VACÍO LLENO

VACUUM FULL ayuda a recuperar el espacio inflado en las tablas e índices. Esta utilidad no se puede utilizar cuando la base de datos está en línea, ya que bloquea la tabla. Las mesas deben someterse a VACUUM FULL solo cuando las aplicaciones están apagadas. Los índices también se reorganizarán junto con las tablas durante VACUUM FULL.

Echemos un vistazo al impacto de VACUUM ANALYZE

Inflamaciones:¿Cómo identificar las inflamaciones? ¿Cuándo se generan los bloats?

Aquí hay algunas pruebas:

Tengo una tabla de tamaño 1 GB con 10 millones de filas.

postgres=# select pg_relation_size('pgbench_accounts')/1024/1024/1024;

 ?column? 
----------------
        1

postgres=# select count(*) From pgbench_accounts ;
  count   
-----------------
 10000000

Veamos el impacto de los bloats en una consulta simple:select * from pgbench_accounts;

A continuación se muestra el plan de explicación para la consulta:

postgres=# explain analyze select * from pgbench_accounts;

QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------
 Seq Scan on pgbench_accounts  (cost=0.00..263935.00 rows=10000000 width=97) 
 (actual time=0.033..1054.257 rows=10000000 loops=1)
 Planning time: 0.255 ms
 Execution time: 1494.448 ms

Ahora, actualicemos todas las filas de la tabla y veamos el impacto de la consulta SELECT anterior.

postgres=# update pgbench_accounts set abalance=1;
UPDATE 10000000

postgres=# select count(*) From pgbench_accounts ;
  count   
-----------------
 10000000

A continuación se muestra el PLAN DE EXPLICACIÓN de la ejecución de ACTUALIZACIÓN posterior a la consulta.

postgres=# explain analyze select * from pgbench_accounts;

QUERY PLAN                                                             
----------------------------------------------------------------------------------------------------------------------------------------------------------
 Seq Scan on pgbench_accounts  (cost=0.00..527868.39 rows=19999939 width=97) 
 (actual time=404.474..1520.175 rows=10000000 loops=1)
 Planning time: 0.051 ms
 Execution time: 1958.532 ms

El tamaño de la tabla aumentó a 2 GB después de la ACTUALIZACIÓN

postgres=# select pg_relation_size('pgbench_accounts')/1024/1024/1024;

 ?column? 
-----------------
        2

Si puede observar y comparar las cifras de costos del EXPLAIN PLAN anterior, hay una gran diferencia. El costo ha aumentado por un gran margen. Más importante aún, si observa detenidamente, la cantidad de filas (poco más de 19 millones) que se escanean después de la ACTUALIZACIÓN es mayor, casi dos veces las filas existentes reales (10 millones). Eso significa que la cantidad de filas infladas es de más de 9 millones y el tiempo real también aumentó y el tiempo de ejecución aumentó de 1,4 segundos a 1,9 segundos.

Entonces, ese es el impacto de no VACÍAR la TABLA después de la ACTUALIZACIÓN. Los números anteriores de EXPLAIN PLAN significan precisamente que la tabla está inflada.

¿Cómo identificar si la mesa está hinchada? Utilice el módulo de contribución pgstattuple:

postgres=# select * from pgstattuple('pgbench_accounts');
 table_len  | tuple_count | tuple_len  | tuple_percent | dead_tuple_count | dead_tuple_len | dead_tuple_percent | free_space | free_percent 
------------+-------------+------------+---------------+------------------+----------------+--------------------+------------+--------------
 2685902848 |    10000000 | 1210000000 |         45.05 |          9879891 |     1195466811 |              44.51 |   52096468 |         1.94

El número anterior indica que la mitad de la tabla está inflada.

ANALICEMOS AL VACÍO la tabla y veamos el impacto ahora:

postgres=# VACUUM ANALYZE pgbench_accounts ;
VACUUM

postgres=# explain analyze select * from pgbench_accounts;

QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------
 Seq Scan on pgbench_accounts  (cost=0.00..428189.05 rows=10032005 width=97) 
 (actual time=400.023..1472.118 rows=10000000 loops=1)
 Planning time: 4.374 ms
 Execution time: 1913.541 ms

Después de VACUUM ANALYZE, los números de costos han disminuido. Ahora, la cantidad de filas escaneadas se muestra cercana a los 10 millones, además, el tiempo real y el tiempo de ejecución no cambiaron mucho. Esto se debe a que, aunque las inflaciones de la tabla han desaparecido, el tamaño de la tabla que se va a escanear sigue siendo el mismo. A continuación se muestra la publicación de salida pgstattuple VACUUM ANALYZE.

postgres=# select * from pgstattuple('pgbench_accounts');

 table_len  | tuple_count | tuple_len  | tuple_percent | dead_tuple_count | dead_tuple_len | dead_tuple_percent | free_space | free_percent 
------------+-------------+------------+---------------+------------------+----------------+--------------------+------------+--------------
 2685902848 |    10000000 | 1210000000 |         45.05 |             0 |              0 |                  0 | 1316722516 |        49.02

El número anterior indica que todos los bloats (tuplas muertas) han desaparecido.

Veamos el impacto de VACUUM FULL ANALYZE y veamos qué sucede:

postgres=# vacuum full analyze pgbench_accounts ;
VACUUM

postgres=# explain analyze select * from pgbench_accounts;

                            QUERY PLAN                                                            
---------------------------------------------------------------------------
 Seq Scan on pgbench_accounts  (cost=0.00..263935.35 rows=10000035 width=97) 
(actual time=0.015..1089.726 rows=10000000 loops=1)
 Planning time: 0.148 ms
 Execution time: 1532.596 ms

Si observa, los números de tiempo real y tiempo de ejecución son similares a los números antes de ACTUALIZAR. Además, el tamaño de la tabla ahora ha disminuido de 2 GB a 1 GB.

postgres=# select pg_relation_size('pgbench_accounts')/1024/1024/1024;

 ?column? 
-----------------
        1

Ese es el impacto de VACUUM FULL.

FACTOR DE RELLENO

FILLFACTOR es un atributo muy importante que puede marcar una diferencia real en la estrategia de mantenimiento de la base de datos a nivel de tabla e índice. Este valor indica la cantidad de espacio que utilizarán los INSERT dentro de un bloque de datos. El valor predeterminado de FILLFACTOR es 100 %, lo que significa que los INSERTOS pueden utilizar todo el espacio disponible en un bloque de datos. También significa que no hay espacio disponible para ACTUALIZACIONES. Este valor se puede reducir a un cierto valor para tablas muy actualizadas.

Este parámetro se puede configurar para cada tabla y un índice. Si FILLFACTOR está configurado con el valor óptimo, puede ver una diferencia real en el rendimiento de VACUUM y también en el rendimiento de las consultas. En resumen, los valores óptimos de FILLFACTOR aseguran que no se asigne una cantidad innecesaria de bloques.

Veamos el mismo ejemplo anterior -

La tabla tiene un millón de filas

postgres=# select count(*) From pgbench_accounts ;
  count   
-----------------
 10000000

Antes de actualizar el tamaño de la tabla es de 1 GB

postgres=# select pg_relation_size('pgbench_accounts')/1024/1024/1024;

?column? 
--------
   1

postgres=# update pgbench_accounts set abalance=1;
UPDATE 10000000

Después de la actualización, el tamaño de la tabla aumentó a 2 GB después de la ACTUALIZACIÓN

postgres=# select pg_relation_size('pgbench_accounts')/1024/1024/1024;

?column? 
---------
    2

Eso significa que el número de bloques asignados a la mesa ha aumentado en un 100 %. Si se configuró FILLFACTOR, es posible que el tamaño de la tabla no haya aumentado en ese margen.

¿Cómo saber qué valor configurar para FILLFACTOR?

Todo depende de qué columnas se actualicen y del tamaño de las columnas actualizadas. En general, sería bueno evaluar el valor de FILLFACTOR probándolo en las bases de datos de UAT. Si las columnas que se actualizan son, digamos, el 10 % de toda la tabla, considere configurar el factor de relleno en 90 % u 80 %.

Nota importante:
Si cambia el valor de FACTOR DE RELLENO para la tabla existente con los datos, deberá realizar un VACUUM FULL o una reorganización de la tabla para asegurarse de que el valor de FACTOR DE RELLENO esté vigente para los datos existentes.

CONSEJOS PARA ASPIRAR

  • Como se mencionó anteriormente, considere ejecutar el trabajo VACUUM ANALYZE manualmente todas las noches en las tablas más utilizadas, incluso cuando el vacío automático esté habilitado.
  • Considere ejecutar VACUUM ANALYZE en tablas después de INSERT masivo. Esto es importante ya que muchos creen que es posible que no sea necesario VACUUM después de las INSERCIONES.
  • Supervise para asegurarse de que las tablas altamente activas se VACÍEN regularmente consultando la tabla pg_stat_user_tables.
  • Utilice el módulo de contribución pg_stattuple para identificar el tamaño del espacio inflado dentro de los segmentos de la tabla.
  • La utilidad VACUUM FULL no se puede utilizar en sistemas de bases de datos de producción. Considere usar herramientas como pg_reorg o pg_repack que ayudarán a reorganizar tablas e índices en línea sin bloqueos.
  • Asegúrese de que el proceso AUTOVACUUM se ejecute durante más tiempo durante el horario laboral (con mucho tráfico).
  • Habilite el parámetro log_autovacuum_min_duration para registrar los tiempos y la duración de los procesos AUTOVACUUM.
  • Es importante asegurarse de que FILLFACTOR esté configurado con un valor óptimo en índices y tablas de transacciones altas.
Descargue el documento técnico hoy Gestión y automatización de PostgreSQL con ClusterControl Obtenga información sobre lo que necesita saber para implementar, monitorear, administrar y escalar PostgreSQLDescargar el documento técnico

Otros problemas de E/S

Clasificación de discos

Las consultas que realizan la clasificación son otra ocurrencia común en las bases de datos de producción en tiempo real y la mayoría de ellas no se pueden evitar. Las consultas que utilizan cláusulas como GROUP BY, ORDER BY, DISTINCT, CREATE INDEX, VACUUM FULL, etc. realizan la clasificación y la clasificación puede tener lugar en el disco. La clasificación tiene lugar en la memoria si la selección y la clasificación se realizan en función de las columnas indexadas. Aquí es donde los índices compuestos juegan un papel clave. Los índices se almacenan agresivamente en la memoria caché. De lo contrario, si surge la necesidad de clasificar los datos en el disco, el rendimiento se ralentizará drásticamente.

Para garantizar que la clasificación se lleve a cabo en la memoria, se puede utilizar el parámetro work_mem. Este parámetro se puede configurar en un valor tal que toda la clasificación se pueda realizar en la memoria. La principal ventaja de este parámetro es que, además de configurarlo en postgresql.conf, también se puede configurar a nivel de sesión, de usuario o de base de datos. ¿Cuánto debería ser el valor de work_mem? ¿Cómo saber qué consultas están realizando la clasificación del disco? ¿Cómo monitorear las consultas que realizan la clasificación de discos en una base de datos de producción en tiempo real?

La respuesta es:configure el parámetro log_temp_files en un valor determinado. El valor está en bytes, un valor de 0 registra todos los archivos temporales (junto con sus tamaños) generados en el disco debido a la clasificación del disco. Una vez configurado el parámetro, podrá ver los siguientes mensajes en los archivos de registro

2018-06-07 22:48:02.358 IST [4219] LOG:  temporary file: path "base/pgsql_tmp/pgsql_tmp4219.0", size 200425472
2018-06-07 22:48:02.358 IST [4219] STATEMENT:  create index bid_idx on pgbench_accounts(bid);
2018-06-07 22:48:02.366 IST [4219] LOG:  duration: 6421.705 ms  statement: create index bid_idx on pgbench_accounts(bid);

El mensaje anterior significa que la consulta CREATE INDEX estaba realizando la clasificación del disco y ha generado un archivo de tamaño 200425472 bytes que tiene más de 191 MB. Eso significa precisamente que el parámetro work_mem debe configurarse en 191+ MB o más para que esta consulta en particular realice la clasificación de memoria.

Bueno, para las consultas de la aplicación, el parámetro work_mem solo se puede configurar a nivel de usuario. Antes de hacerlo, tenga cuidado con la cantidad de conexiones que el usuario está haciendo a la base de datos y la cantidad de consultas de clasificación que ejecuta ese usuario. Porque PostgreSQL intenta asignar work_mem a cada proceso (realizando la clasificación) en cada conexión, lo que potencialmente podría agotar la memoria en el servidor de la base de datos.

Diseño del sistema de archivos de la base de datos

Diseñar un diseño de sistema de archivos de base de datos eficiente y propicio para el rendimiento es importante desde la perspectiva del rendimiento y la escalabilidad. Es importante destacar que esto no depende del tamaño de la base de datos. En general, la percepción es que las bases de datos de gran tamaño necesitarán una arquitectura de disco de alto rendimiento, lo cual NO es cierto. Incluso si el tamaño de la base de datos es de 50 GB, es posible que necesite una buena arquitectura de disco. Y esto puede no ser posible sin incurrir en costos adicionales.

Aquí hay algunos CONSEJOS para lo mismo:

  • Asegúrese de que la base de datos tenga varios espacios de tabla, con tablas e índices agrupados según las tasas de transacción.
  • El tablespace se debe colocar en varios sistemas de archivos de disco para una E/S equilibrada. Esto también garantizará que varias CPU entren en juego para realizar transacciones en varios discos.
  • Considere colocar el directorio pg_xlog o pg_wal en un disco separado en una base de datos de transacciones altas.
  • Asegúrese de que los parámetros *_cost estén configurados en función de la infraestructura
  • Use iostat, mpstat y otras herramientas de monitoreo de E/S para comprender las estadísticas de E/S en todos los discos y diseñar/administrar los objetos de la base de datos en consecuencia.

PostgreSQL en la nube

La infraestructura es fundamental para el buen rendimiento de la base de datos. Las estrategias de ingeniería de rendimiento difieren según la infraestructura y el entorno. Se debe tener especial cuidado con las bases de datos PostgreSQL alojadas en la nube. La evaluación comparativa del rendimiento de las bases de datos alojadas en servidores barebone físicos en un centro de datos local puede ser completamente diferente de las bases de datos alojadas en la nube pública.

En general, las instancias en la nube pueden ser un poco más lentas y los puntos de referencia difieren por un margen considerable, especialmente en términos de E/S. Realice siempre comprobaciones de latencia de E/S antes de elegir/construir una instancia de nube. Para mi sorpresa, aprendí que el rendimiento de las instancias de la nube también puede variar según las regiones, aunque sean del mismo proveedor de la nube. Para explicar esto con más detalle, una instancia en la nube con las mismas especificaciones construidas en dos regiones diferentes podría brindarle resultados de rendimiento diferentes.

Carga masiva de datos

Las operaciones de carga masiva de datos sin conexión son bastante comunes en el mundo de las bases de datos. Pueden generar una carga de E/S significativa, lo que a su vez ralentiza el rendimiento de la carga de datos. Me he enfrentado a tales desafíos en mi experiencia como DBA. A menudo, la carga de datos se vuelve terriblemente lenta y debe ajustarse. Aquí hay algunos consejos. Tenga en cuenta que estos se aplican solo a las operaciones de carga de datos fuera de línea y no se pueden considerar para la carga de datos en la base de datos de producción en vivo.

  • Dado que la mayoría de las operaciones de carga de datos se llevan a cabo fuera del horario laboral, asegúrese de configurar los siguientes parámetros durante la carga de datos:
    • Configure valores relacionados con puntos de control lo suficientemente grandes para que los puntos de control no causen problemas de rendimiento.
    • Desactivar full_page_write
    • Desactivar el archivo wal
    • Configure el parámetro synchronous_commit en "off"
    • Elimine las restricciones y los índices de las tablas sujetas a la carga de datos (las restricciones y los índices se pueden volver a crear después de la carga de datos con un valor de work_mem mayor)
    • Si está realizando la carga de datos desde un archivo CSV, un mayor maintenance_work_mem puede brindarle buenos resultados.
    • Aunque habrá un beneficio significativo en el rendimiento, NO desactive el parámetro fsync ya que podría dañar los datos.

CONSEJOS para el análisis del rendimiento de la nube

  • Realice pruebas exhaustivas de latencia de E/S con pgbench. En mi experiencia, obtuve resultados de rendimiento bastante normales al realizar comprobaciones de latencia de disco como parte de la evaluación de TPS. Hubo problemas con el rendimiento de la memoria caché en algunas instancias de nube pública. Esto ayudará a elegir las especificaciones adecuadas para la instancia de nube elegida para las bases de datos.
  • Las instancias en la nube pueden funcionar de manera diferente de una región a otra. Una instancia de nube con determinadas especificaciones en una región puede generar resultados de rendimiento diferentes en comparación con una instancia de nube con las mismas especificaciones en otra región. Mis pruebas de pgbench ejecutadas en varias instancias de la nube (todas con las mismas especificaciones con el mismo proveedor de la nube) en diferentes regiones me dieron resultados diferentes en algunas de ellas. Esto es importante especialmente cuando está migrando a la nube.
  • Es posible que el rendimiento de las consultas en la nube necesite un enfoque de ajuste diferente. Los administradores de bases de datos deberán usar los parámetros *_cost para garantizar que se generen planes de ejecución de consultas saludables.

Tools to Monitor PostgreSQL Performance

There are various tools to monitor PostgreSQL performance. Let me highlight some of those.

  • pg_top is a GREAT tool to monitor PostgreSQL database dynamically. I would highly recommend this tool for DBAs for various reasons. This tool has numerous advantages, let me list them out:
    • pg_top tool uses textual interface and is similar to Unix “top” utility.
    • Will clearly list out the processes and the hardware resources utilized. What excites me with this tool is that it will clearly tell you if a particular process is currently on DISK or CPU - in my view that’s excellent. DBAs can clearly pick the process running for longer time on the disk.
    • You can check the EXPLAIN PLAN of the top SQLs dynamically or instantly
    • You can also find out what Tables or Indexes are being scanned instantly
  • Nagios is a popular monitoring tool for PostgreSQL which has both open-source and commercial versions. Open source version should suffice for monitoring. Custom Perl scripts can be built and plugged into Nagios module.
  • Pgbadger is a popular tool which can be used to analyze PostgreSQL log files and generate performance reports. This report can be used to analyze the performance of checkpoints, disk sorting.
  • Zabbix is another popular tool used for PostgreSQL monitoring.

ClusterControl is an up-and-coming management platform for PostgreSQL. Apart from monitoring, it also has functionality to deploy replication setups with load balancers, automatic failover, backup management, among others.