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.