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

Desempeño de Secuencias y Seriales en Postgres-XL

En Postgres-XL, las secuencias se mantienen en el Administrador de transacciones globales (GTM) para garantizar que se les asignen valores que no entren en conflicto cuando se incrementan desde varios nodos. Esto agrega una sobrecarga significativa para una consulta que realiza miles de INSERCIONES en una tabla con una columna en serie, incrementando la secuencia de una en una y haciendo un viaje de ida y vuelta de la red al GTM, para cada INSERCIÓN.

Shaun Thomas en un blog reciente se quejó de que los INSERT funcionan mucho más lentos en Postgres-XL en comparación con PostgreSQL estándar. Ya existe una forma de mejorar el rendimiento de las secuencias, pero claramente no está bien publicitada. Pensé que esta era una buena oportunidad para explicar las instalaciones.

Postgres-XL proporciona un GUC configurable por el usuario llamado sequence_range . Cada backend solicita un bloque de valores de secuencia controlados por este GUC. Dado que COPY se usa comúnmente para cargar datos en masa en Postgres, Postgres-XL anula automáticamente este GUC durante la operación COPY y lo establece en 1000, lo que mejora drásticamente el rendimiento de COPY. Desafortunadamente, para los INSERT regulares, el valor predeterminado es 1 y, a menos que el usuario establezca explícitamente sequence_range a un valor razonablemente más alto, el rendimiento de INSERT sufre. Aquí hay un ejemplo, usando el mismo esquema de muestra que usó Shaun en su publicación de blog.

CREATE TABLE sensor_log (
  sensor_log_id  SERIAL PRIMARY KEY,
  location       VARCHAR NOT NULL,
  reading        BIGINT NOT NULL,
  reading_date   TIMESTAMP NOT NULL
) DISTRIBUTE BY HASH (sensor_log_id);

postgres=# \timing
Timing is on.
postgres=# INSERT INTO sensor_log (location, reading, reading_date)                                                                                                                         SELECT s.id % 1000, s.id % 100, now() - (s.id || 's')::INTERVAL                                                                                                                    FROM generate_series(1, 40000) s(id);
INSERT 0 40000
Time: 12067.911 ms

postgres=# set sequence_range TO 1000;
SET
Time: 1.231 ms
postgres=# INSERT INTO sensor_log (location, reading, reading_date)                                                                                                                         SELECT s.id % 1000, s.id % 100, now() - (s.id || 's')::INTERVAL                                                                                                                    FROM generate_series(1, 40000) s(id);
INSERT 0 40000
Time: 397.406 ms

Entonces, al configurar adecuadamente sequence_range a 1000, el rendimiento de la consulta INSERT mejoró casi 30 veces.

Cuando se agregó esta característica, el valor predeterminado de secuencia_rango GUC se estableció en 1 porque puede dejar huecos en los valores de secuencia. Pero observando las implicaciones de rendimiento para un caso de uso muy común, decidimos aumentar el valor predeterminado a 1000 y ahora se ha confirmado en la rama XL9_5_STABLE del repositorio.

Es importante tener en cuenta que mientras un valor alto de sequence_range mejorará el rendimiento de las secuencias y las publicaciones seriadas, también puede dejar grandes agujeros en los rangos de secuencias, ya que los rangos de secuencias se almacenan en caché a nivel de back-end. Para solucionar este problema, Postgres-XL comienza con el valor del parámetro CACHE especificado que se usa en el momento de la creación de la secuencia y lo duplica cada vez (limitado por el rango_secuencia) si las secuencias se consumen a un ritmo muy alto.

También se puede lograr una mejora similar aumentando el valor del parámetro CACHE de la secuencia para que una parte de los valores de secuencia se almacenen en caché en el nivel de back-end. El siguiente ejemplo muestra cómo hacerlo para una columna serial. Pero el sequence_range GUC proporciona una manera fácil de anular el valor predeterminado global y también garantiza que las secuencias se almacenen en caché solo cuando se incrementan muy rápidamente.

postgres=# ALTER SEQUENCE sensor_log_sensor_log_id_seq CACHE 1000;                                                                                                             ALTER SEQUENCE
Time: 8.683 ms
postgres=# SET sequence_range TO 1;
SET
Time: 2.341 ms
postgres=# INSERT INTO sensor_log (location, reading, reading_date)                                                                                                            SELECT s.id % 1000, s.id % 100, now() - (s.id || 's')::INTERVAL                                                                                                                  FROM generate_series(1, 40000) s(id);
INSERT 0 40000
Time: 418.068 ms

Puede elegir cualquiera de estas técnicas para mejorar el rendimiento. Aunque ahora que el valor predeterminado de sequence_range se cambia a 1000, es posible que no muchos usuarios vean la diferencia en el rendimiento.