sql >> Databáze >  >> RDS >> PostgreSQL

Výkon sekvencí a seriálů v Postgres-XL

V Postgres-XL jsou sekvence udržovány v Global Transaction Manager (GTM), aby bylo zajištěno, že jim budou přiřazeny nekonfliktní hodnoty, když jsou inkrementovány z více uzlů. To zvyšuje značnou režii pro dotaz, který provádí tisíce INSERTů v tabulce se sériovým sloupcem, zvyšuje sekvenci jeden po druhém a provádí zpáteční cestu k GTM pro každý INSERT.

Shaun Thomas si v nedávném blogu stěžoval na INSERTy běžící na Postgres-XL mnohem pomaleji ve srovnání s vanilla PostgreSQL. Již existuje způsob, jak zlepšit výkon sekvencí, ale zjevně není dobře propagován. Myslel jsem, že je to dobrá příležitost k vysvětlení zařízení.

Postgres-XL poskytuje uživatelsky nastavitelný GUC s názvem sequence_range . Každý backend požaduje blok sekvenčních hodnot řízených tímto GUC. Vzhledem k tomu, že COPY se v Postgresu běžně používá k hromadnému načítání dat, Postgres-XL automaticky přepíše tento GUC během operace COPY a nastaví ho na 1000, čímž se dramaticky zlepší výkon COPY. Bohužel pro běžné INSERTy je výchozí hodnota 1 a pokud uživatel výslovně nenastaví rozsah_sekvence na přiměřeně vyšší hodnotu, utrpí výkon INSERT. Zde je příklad s použitím stejného vzorového schématu, jaké použil Shaun ve svém příspěvku na blogu.

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

Tedy vhodným nastavením rozsah_sekvence na 1000, výkon dotazu INSERT se zlepšil téměř 30krát.

Když byla tato funkce přidána, výchozí hodnota sekvence_rozsahu GUC byla nastavena na 1, protože může zanechat v hodnotách sekvence díry. Ale podíváme-li se na důsledky pro výkon u velmi běžného případu použití, rozhodli jsme se zvýšit výchozí hodnotu na 1000 a toto bylo nyní převedeno na větev XL9_5_STABLE úložiště.

Je důležité poznamenat, že zatímco vysoká hodnota rozsah_sekvence zlepší výkon sekvencí a seriálů, může také zanechat velké díry v rozsahu sekvencí, protože rozsahy sekvencí jsou ukládány do mezipaměti na úrovni backendu. Aby se tento problém vyřešil, Postgres-XL začíná se zadanou hodnotou parametru CACHE použitou při vytváření sekvence a pokaždé ji zdvojnásobuje (omezeno rozsahem sekvence), pokud jsou sekvence spotřebovávány velmi vysokou rychlostí.

Podobného zlepšení lze také dosáhnout zvýšením hodnoty parametru CACHE sekvence, takže část hodnot sekvencí je uložena do mezipaměti na úrovni backendu. Následující příklad ukazuje, jak to udělat pro sériový sloupec. Ale rozsah_sekvence GUC poskytuje snadný způsob, jak přepsat globální výchozí nastavení, a také zajišťuje, že sekvence jsou ukládány do mezipaměti pouze tehdy, když jsou velmi rychle inkrementovány.

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

Pro zlepšení výkonu si můžete vybrat kteroukoli z těchto technik. I když nyní je výchozí hodnota rozsah_sekvence je změněno na 1000, málokdo si všimne rozdílu ve výkonu.


  1. Oracle PL/SQL:Zkontrolujte, zda je BLOB nebo CLOB prázdný

  2. Správa uživatelských účtů, role, oprávnění, autentizace PHP a MySQL -- Část 5

  3. Jak získat velikost tabulky v MySQL

  4. Spuštění klastru MariaDB Galera bez nástrojů pro orchestraci – DB Container Management:Část druhá