PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Esecuzione di sequenze e seriali in Postgres-XL

In Postgres-XL, le sequenze vengono mantenute nel Global Transaction Manager (GTM) per garantire che vengano assegnati valori non in conflitto quando vengono incrementate da più nodi. Ciò aggiunge un sovraccarico significativo per una query che esegue migliaia di INSERT in una tabella con una colonna seriale, incrementando la sequenza uno alla volta ed effettuando un roundtrip di rete al GTM, per ogni INSERT.

Shaun Thomas in un recente blog si è lamentato del fatto che gli INSERT funzionano di una grandezza più lenta su Postgres-XL rispetto a PostgreSQL vaniglia. Esiste già un modo per migliorare le prestazioni per le sequenze, ma chiaramente non è ben pubblicizzato. Ho pensato che questa fosse una buona opportunità per spiegare la struttura.

Postgres-XL fornisce un GUC impostabile dall'utente chiamato sequence_range . Ogni back-end richiede un blocco di valori di sequenza come controllato da questo GUC. Dato che COPY è comunemente usato per caricare in blocco i dati in Postgres, Postgres-XL sovrascrive automaticamente questo GUC durante l'operazione di COPIA e lo imposta su 1000, migliorando così notevolmente le prestazioni di COPIA. Sfortunatamente, per gli INSERT regolari, il valore predefinito è 1 e, a meno che l'utente non imposti esplicitamente sequence_range a un valore ragionevolmente superiore, le prestazioni INSERT ne risentono. Ecco un esempio, utilizzando lo stesso schema di esempio utilizzato da Shaun nel suo post sul 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

Quindi impostando opportunamente sequence_range a 1000, le prestazioni della query INSERT sono migliorate di quasi 30 volte.

Quando questa funzione è stata aggiunta, il valore predefinito di sequenza_intervallo GUC è stato impostato su 1 perché può lasciare buchi nei valori della sequenza. Ma guardando le implicazioni sulle prestazioni per un caso d'uso molto comune, abbiamo deciso di aumentare il valore predefinito a 1000 e questo è stato ora assegnato al ramo XL9_5_STABLE del repository.

È importante notare che mentre un valore elevato di sequence_range migliorerà le prestazioni per sequenze e serial, può anche lasciare grandi buchi negli intervalli di sequenze poiché gli intervalli di sequenze sono memorizzati nella cache a livello di back-end. Per risolvere questo problema, Postgres-XL inizia con il valore del parametro CACHE specificato utilizzato al momento della creazione della sequenza e lo raddoppia ogni volta (limitato da sequenza_intervallo) se le sequenze vengono consumate a una velocità molto elevata.

Un miglioramento simile può essere ottenuto anche aumentando il valore del parametro CACHE della sequenza in modo che un blocco di valori di sequenza venga memorizzato nella cache a livello di back-end. L'esempio seguente mostra come farlo per una colonna seriale. Ma il sequence_range GUC fornisce un modo semplice per ignorare l'impostazione predefinita globale e garantisce anche che le sequenze vengano memorizzate nella cache solo quando vengono incrementate molto 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

Puoi scegliere una di queste tecniche per migliorare le prestazioni. Anche se ora è il valore predefinito di sequence_range è cambiato in 1000, non molti utenti potrebbero notare la differenza di prestazioni.