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

Udførelse af sekvenser og serier i Postgres-XL

I Postgres-XL vedligeholdes sekvenser i Global Transaction Manager (GTM) for at sikre, at de tildeles ikke-modstridende værdier, når de inkrementeres fra flere noder. Dette tilføjer betydelig overhead for en forespørgsel, der udfører tusindvis af INSERTs i en tabel med en seriel kolonne, øger sekvensen én ad gangen og laver en netværksrundtur til GTM, for hver INSERT.

Shaun Thomas klagede i en nylig blog over INSERT'er, der kører langsommere på Postgres-XL sammenlignet med vanilla PostgreSQL. Der er allerede en måde at forbedre ydeevnen for sekvenser på, men det er tydeligvis ikke godt annonceret. Jeg tænkte, at dette er en god mulighed for at forklare faciliteten.

Postgres-XL giver en brugerindstillelig GUC kaldet sequence_range . Hver backend anmoder om en blok af sekvensværdier som kontrolleret af denne GUC. Da COPY populært bruges til at samle data i Postgres, tilsidesætter Postgres-XL automatisk denne GUC under COPY-drift og indstiller den til 1000, hvilket forbedrer COPY-ydeevnen dramatisk. For almindelige INSERTs er standardindstillingen desværre 1, og medmindre brugeren udtrykkeligt angiver sequence_range til en rimelig højere værdi, lider INSERT ydeevne. Her er et eksempel, der bruger det samme eksempelskema som brugt af Shaun i hans blogindlæg.

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

Så ved at indstille sequence_range korrekt til 1000, blev INSERT-forespørgslens ydeevne forbedret med næsten 30 gange.

Da denne funktion blev tilføjet, blev standardværdien for sequence_range GUC sat til 1, fordi den kan efterlade huller i sekvensværdierne. Men ser vi på præstationsimplikationerne for en meget almindelig anvendelse, besluttede vi at øge standarden til 1000, og dette er nu blevet forpligtet til XL9_5_STABLE-grenen af ​​depotet.

Det er vigtigt at bemærke, at mens en høj værdi af sequence_range vil forbedre ydeevnen for sekvenser og serier, kan den også efterlade store huller i sekvensintervaller, da sekvensintervallerne er cachelagret på et backend-niveau. For at løse dette problem starter Postgres-XL med den specificerede CACHE-parameterværdi, der bruges ved sekvensoprettelsestidspunktet og fordobler den hver gang (begrænset af sequence_range), hvis sekvenser forbruges med en meget høj hastighed.

Lignende forbedringer kan også opnås ved at øge sekvensens CACHE-parameterværdi, så en del af sekvensværdier cachelagres på backend-niveau. Følgende eksempel viser, hvordan man gør det for en seriel kolonne. Men sequence_range GUC giver en nem måde at tilsidesætte den globale standard og sikrer også, at sekvenserne kun cachelagres, når de øges meget hurtigt.

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

Du kan vælge en af ​​disse teknikker for at forbedre ydeevnen. Selvom det nu er standardværdien for sequence_range er ændret til 1000, er der ikke mange brugere, der kan se forskellen i ydeevne.


  1. 2 måder at liste alle triggere i en PostgreSQL-database

  2. Introduktion til SQL-gruppering og sammenlægning

  3. Ti tips til at gå i produktion med PostgreSQL

  4. Sådan tilføjes Computed Column i SQL Server Table - SQL Server / T-SQL vejledning del 47