PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Jak mogę się upewnić, że widok zmaterializowany jest zawsze aktualny?

Muszę wywołać REFRESH MATERIALIZED VIEW po każdej zmianie w odpowiednich tabelach, prawda?

Tak, sam PostgreSQL nigdy nie wywoła go automatycznie, musisz to zrobić w jakiś sposób.

Jak mam to zrobić?

Wiele sposobów na osiągnięcie tego. Zanim podasz kilka przykładów, pamiętaj, że REFRESH MATERIALIZED VIEW polecenie blokuje widok w trybie AccessExclusive, więc gdy działa, nie możesz nawet wykonać SELECT na stole.

Chociaż, jeśli jesteś w wersji 9.4 lub nowszej, możesz nadać jej CONCURRENTLY opcja:

REFRESH MATERIALIZED VIEW CONCURRENTLY my_mv;

Spowoduje to uzyskanie ExclusiveLock i nie zablokuje SELECT zapytań, ale może mieć większy narzut (w zależności od ilości zmienionych danych, jeśli zmieniło się kilka wierszy, może być szybciej). Chociaż nadal nie możesz uruchomić dwóch REFRESH komendy jednocześnie.

Odśwież ręcznie

Jest to opcja do rozważenia. Szczególnie w przypadku ładowania danych lub aktualizacji wsadowych (np. system, który ładuje tylko tony informacji/danych po długim okresie czasu) często wykonuje się operacje na końcu modyfikacji lub przetwarzania danych, więc można po prostu dołączyć REFRESH operacja na końcu.

Planowanie operacji ODŚWIEŻ

Pierwszą i powszechnie stosowaną opcją jest użycie jakiegoś systemu planowania do wywołania odświeżania, na przykład możesz skonfigurować to w zadaniu cron:

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

A następnie Twój zmaterializowany widok będzie odświeżany co 30 minut.

Rozważania

Ta opcja jest naprawdę dobra, szczególnie w przypadku CONCURRENTLY opcja, ale tylko wtedy, gdy możesz zaakceptować, że dane nie są przez cały czas aktualne w 100%. Pamiętaj, że nawet z lub bez CONCURRENTLY , REFRESH polecenie musi uruchomić całe zapytanie, więc musisz poświęcić czas potrzebny na uruchomienie wewnętrznego zapytania przed rozważeniem czasu na zaplanowanie REFRESH .

Odświeżanie za pomocą wyzwalacza

Inną opcją jest wywołanie REFRESH MATERIALIZED VIEW w funkcji wyzwalacza, na przykład:

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

Następnie w dowolnej tabeli, która obejmuje zmiany w widoku, wykonaj:

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

Rozważania

Ma kilka krytycznych pułapek dla wydajności i współbieżności:

  1. Każda operacja INSERT/UPDATE/DELETE będzie musiała wykonać zapytanie (co może być powolne, jeśli rozważasz MV);
  2. Nawet z CONCURRENTLY , jedno REFRESH nadal blokuje inny, więc wszelkie INSERT/UPDATE/DELETE w zaangażowanych tabelach zostaną zserializowane.

Jedyną sytuacją, którą uważam za dobry pomysł, jest to, że zmiany są naprawdę rzadkie.

Odśwież przy użyciu opcji LISTEN/NOTIFY

Problem z poprzednią opcją polega na tym, że jest ona synchroniczna i nakłada duże obciążenie na każdą operację. Aby to poprawić, możesz użyć wyzwalacza jak poprzednio, ale wywołuje on tylko NOTIFY operacja:

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

Możesz więc zbudować aplikację, która pozostanie połączona i używa LISTEN operacja identyfikująca potrzebę wywołania REFRESH . Jednym fajnym projektem, którego możesz użyć do przetestowania tego, jest pgsidekick, z tym projektem możesz użyć skryptu powłoki do wykonania LISTEN , dzięki czemu możesz zaplanować REFRESH jako:

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

Lub użyj pglater (również wewnątrz pgsidekick ), aby upewnić się, że nie wywołasz REFRESH bardzo często. Na przykład możesz użyć następującego wyzwalacza, aby go REFRESH , ale w ciągu 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;
$$;

Więc nie wywoła funkcji REFRESH w mniej niż 60 sekund, a także jeśli NOTIFY wielokrotnie w czasie krótszym niż 60 sekund, REFRESH zostanie wyzwolony tylko raz.

Rozważania

Jako opcja crona, ta również jest dobra tylko wtedy, gdy możesz znieść trochę przestarzałych danych, ale ma to tę zaletę, że REFRESH jest wywoływana tylko wtedy, gdy jest to naprawdę potrzebne, więc masz mniej narzutów, a także dane są aktualizowane bliżej, gdy jest to potrzebne.

OBS:Tak naprawdę nie wypróbowałem jeszcze kodów i przykładów, więc jeśli ktoś znajdzie błąd, literówkę lub spróbuje i działa (lub nie), daj mi znać.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PostgreSQL usuń całą zawartość

  2. Błąd połączenia z Postgresem w Spring Boot

  3. Jak sprawić, by wyliczenia Java i Postgres współpracowały ze sobą w celu aktualizacji?

  4. Dlaczego Postgres mówi, że kolumna nie istnieje?

  5. 3 sposoby sprawdzenia typu danych kolumny w PostgreSQL