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

Jak mohu zajistit, aby byl materializovaný pohled vždy aktuální?

Budu muset vyvolat REFRESH MATERIALIZED VIEW při každé změně příslušných tabulek, že?

Ano, PostgreSQL to sám o sobě nikdy nezavolá automaticky, musíte to nějakým způsobem udělat.

Jak to mám udělat?

Mnoho způsobů, jak toho dosáhnout. Než uvedete nějaké příklady, mějte na paměti, že REFRESH MATERIALIZED VIEW příkaz blokuje zobrazení v režimu AccessExclusive, takže když funguje, nemůžete ani provést SELECT na stole.

Pokud jste ve verzi 9.4 nebo novější, můžete mu dát CONCURRENTLY možnost:

REFRESH MATERIALIZED VIEW CONCURRENTLY my_mv;

Tím získáte ExclusiveLock a neblokujete SELECT dotazy, ale může mít větší režii (závisí na množství změněných dat, pokud se změnilo několik řádků, může to být rychlejší). I když stále nemůžete spustit dva REFRESH příkazy současně.

Obnovit ručně

Je to možnost ke zvážení. Speciálně v případech načítání dat nebo dávkových aktualizací (např. systém, který načítá jen tuny informací/dat po dlouhé době) je běžné mít na konci operace pro úpravu nebo zpracování dat, takže můžete jednoduše zahrnout REFRESH operace na konci.

Naplánování operace REFRESH

První a široce používanou možností je použít nějaký plánovací systém k vyvolání obnovy, například byste mohli nakonfigurovat v úloze cron:

*/30 * * * * psql -d your_database -c "REFRESH MATERIALIZED VIEW CONCURRENTLY my_mv"

A pak se váš zhmotněný pohled obnoví každých 30 minut.

Úvahy

Tato možnost je opravdu dobrá, zvláště s CONCURRENTLY možnost, ale pouze v případě, že můžete akceptovat, že data nejsou neustále 100% aktuální. Mějte na paměti, že i s nebo bez CONCURRENTLY , REFRESH příkaz potřebuje spustit celý dotaz, takže musíte věnovat čas potřebný ke spuštění vnitřního dotazu, než zvážíte čas na naplánování REFRESH .

Obnovení pomocí spouštěče

Další možností je zavolat REFRESH MATERIALIZED VIEW ve spouštěcí funkci, jako je tato:

CREATE OR REPLACE FUNCTION tg_refresh_my_mv()
RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
    REFRESH MATERIALIZED VIEW CONCURRENTLY my_mv;
    RETURN NULL;
END;
$$;

Poté v jakékoli tabulce, která zahrnuje změny v pohledu, provedete:

CREATE TRIGGER tg_refresh_my_mv AFTER INSERT OR UPDATE OR DELETE
ON table_name
FOR EACH STATEMENT EXECUTE PROCEDURE tg_refresh_my_mv();

Úvahy

Má některá kritická úskalí pro výkon a souběžnost:

  1. Jakákoli operace INSERT/UPDATE/DELETE bude muset provést dotaz (což může být pomalé, pokud uvažujete o MV);
  2. Dokonce i s CONCURRENTLY , jeden REFRESH stále blokuje další, takže jakékoli INSERT/UPDATE/DELETE v příslušných tabulkách budou serializovány.

Jediná situace, kterou považuji za dobrý nápad, je, pokud jsou změny opravdu vzácné.

Obnovte pomocí LISTEN/NOTIFY

Problém s předchozí možností je, že je synchronní a vyžaduje velkou režii na každou operaci. Chcete-li to zlepšit, můžete použít spouštěč jako dříve, ale volá pouze NOTIFY operace:

CREATE OR REPLACE FUNCTION tg_refresh_my_mv()
RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
    NOTIFY refresh_mv, 'my_mv';
    RETURN NULL;
END;
$$;

Pak můžete vytvořit aplikaci, která zůstane připojená a bude používat LISTEN operaci k identifikaci potřeby zavolat REFRESH . Jeden pěkný projekt, který můžete použít k otestování, je pgsidekick, s tímto projektem můžete použít skript shellu k provedení LISTEN , takže můžete naplánovat REFRESH jako:

pglisten --listen=refresh_mv --print0 | xargs -0 -n1 -I? psql -d your_database -c "REFRESH MATERIALIZED VIEW CONCURRENTLY ?;"

Nebo použijte pglater (také uvnitř pgsidekick ), abyste se ujistili, že nevoláte REFRESH velmi často. Můžete například použít následující spouštěč k tomu, aby byl REFRESH , ale do 1 minuty (60 sekund):

CREATE OR REPLACE FUNCTION tg_refresh_my_mv()
RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
    NOTIFY refresh_mv, '60 REFRESH MATERIALIZED VIEW CONCURRENLTY my_mv';
    RETURN NULL;
END;
$$;

Nebude tedy volat REFRESH za méně než 60 sekund od sebe a také pokud NOTIFY mnohokrát za méně než 60 sekund, REFRESH se spustí pouze jednou.

Úvahy

Jako možnost cronu je tato také dobrá pouze v případě, že si vystačíte s málo zastaralými daty, ale má tu výhodu, že REFRESH je volána pouze tehdy, když je to skutečně potřeba, takže máte méně režie a také se data aktualizují blíže tomu, kdy je potřeba.

OBS:Kódy a příklady jsem ještě pořádně nezkoušel, takže pokud někdo najde chybu, překlep nebo to vyzkouší a funguje (nebo ne), dejte mi prosím vědět.



  1. Základní příkazy pro správu databáze MySQL – část I

  2. Jak implementovat LIMIT s SQL Server?

  3. Metoda sběru:Funkce COUNT v databázi Oracle

  4. Co je STATISTICS TIME v SQL Server?