PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Desempenho de Sequências e Seriados no Postgres-XL


No Postgres-XL, as sequências são mantidas no Global Transaction Manager (GTM) para garantir que sejam atribuídos valores não conflitantes quando são incrementados de vários nós. Isso adiciona uma sobrecarga significativa para uma consulta fazendo milhares de INSERTs em uma tabela com uma coluna serial, incrementando uma sequência de cada vez e fazendo uma viagem de ida e volta da rede para o GTM, para cada INSERT.

Shaun Thomas em um blog recente reclamou sobre INSERTs rodando uma magnitude mais lenta no Postgres-XL em comparação com o PostgreSQL vanilla. Já existe uma maneira de melhorar o desempenho das sequências, mas claramente não é bem divulgada. Eu pensei que esta é uma boa oportunidade para explicar a instalação.

Postgres-XL fornece um GUC configurável pelo usuário chamado sequence_range . Cada backend solicita um bloco de valores de sequência conforme controlado por este GUC. Dado que COPY é popularmente usado para carregar dados em massa no Postgres, o Postgres-XL substitui automaticamente este GUC durante a operação COPY e o define como 1000, melhorando drasticamente o desempenho do COPY. Infelizmente, para INSERTs regulares, o padrão é 1 e, a menos que o usuário defina explicitamente sequence_range para um valor razoavelmente mais alto, o desempenho de INSERT é prejudicado. Aqui está um exemplo, usando o mesmo esquema de amostra usado por Shaun em sua postagem no 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

Então, definindo adequadamente sequence_range para 1000, o desempenho da consulta INSERT melhorou quase 30 vezes.

Quando esse recurso foi adicionado, o valor padrão de sequence_range GUC foi definido como 1 porque pode deixar lacunas nos valores de sequência. Mas olhando para as implicações de desempenho para um caso de uso muito comum, decidimos aumentar o padrão para 1000 e isso agora foi confirmado na ramificação XL9_5_STABLE do repositório.

É importante observar que, embora um valor alto de sequence_range melhorará o desempenho de sequências e seriais, também pode deixar grandes lacunas nos intervalos de sequência, pois os intervalos de sequência são armazenados em cache em um nível de back-end. Para resolver esse problema, o Postgres-XL inicia com o valor do parâmetro CACHE especificado usado no momento da criação da sequência e o duplica todas as vezes (limitado por sequence_range) se as sequências estiverem sendo consumidas em uma taxa muito alta.

Uma melhoria semelhante também pode ser alcançada aumentando o valor do parâmetro CACHE da sequência para que uma parte dos valores da sequência seja armazenada em cache no nível de back-end. O exemplo a seguir mostra como fazer isso para uma coluna serial. Mas o sequence_range O GUC fornece uma maneira fácil de substituir o padrão global e também garante que as sequências sejam armazenadas em cache somente quando forem incrementadas muito rapidamente.
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

Você pode escolher qualquer uma dessas técnicas para melhorar o desempenho. Embora agora que o valor padrão de sequence_range for alterado para 1000, muitos usuários não verão a diferença no desempenho.