PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Как мога да гарантирам, че материализираният изглед винаги е актуален?

Ще трябва да извикам REFRESH MATERIALIZED VIEW при всяка промяна на съответните таблици, нали?

Да, PostgreSQL сам по себе си никога няма да го извика автоматично, трябва да го направите по някакъв начин.

Как трябва да направя това?

Много начини да постигнете това. Преди да дадете някои примери, имайте предвид, че REFRESH MATERIALIZED VIEW командата блокира изгледа в режим AccessExclusive, така че докато работи, дори не можете да направите SELECT на масата.

Въпреки че, ако сте във версия 9.4 или по-нова, можете да й дадете CONCURRENTLY опция:

REFRESH MATERIALIZED VIEW CONCURRENTLY my_mv;

Това ще придобие ExclusiveLock и няма да блокира SELECT заявки, но може да има по-големи допълнителни разходи (зависи от количеството променени данни, ако са променени няколко реда, тогава може да е по-бързо). Въпреки че все още не можете да стартирате две REFRESH команди едновременно.

Опреснете ръчно

Това е вариант за разглеждане. Специално в случаи на зареждане на данни или пакетни актуализации (например система, която зарежда само тонове информация/данни след дълги периоди от време) е обичайно да има операции в края за промяна или обработка на данните, така че можете просто да включите REFRESH операция в края му.

Насрочване на операцията ОБНОВЯВАНЕ

Първата и широко използвана опция е да използвате някаква система за планиране, за да извикате опресняването, например, можете да конфигурирате подобно в задание на cron:

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

И тогава материализираният ви изглед ще се обновява на всеки 30 минути.

Съображения

Тази опция е наистина добра, особено с CONCURRENTLY опция, но само ако можете да приемете данните да не са 100% актуални през цялото време. Имайте предвид, че дори със или без CONCURRENTLY , REFRESH командата трябва да изпълни цялата заявка, така че трябва да отделите времето, необходимо за изпълнение на вътрешната заявка, преди да обмислите времето за насрочване на REFRESH .

Опресняване със задействане

Друга възможност е да извикате REFRESH MATERIALIZED VIEW в тригерна функция, като тази:

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

След това във всяка таблица, която включва промени в изгледа, правите:

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

Съображения

Той има някои критични клопки за производителност и едновременност:

  1. Всяка операция INSERT/UPDATE/DELETE ще трябва да изпълни заявката (което е възможно бавно, ако обмисляте MV);
  2. Дори с CONCURRENTLY , едно REFRESH все още блокира друг, така че всяко INSERT/UPDATE/DELETE в участващите таблици ще бъде сериализирано.

Единствената ситуация, която мога да смятам за добра идея е, ако промените са наистина редки.

Опреснете чрез LISTEN/NOTIFY

Проблемът с предишния вариант е, че е синхронен и налага големи разходи при всяка операция. За да подобрите това, можете да използвате тригер както преди, но това извиква само NOTIFY операция:

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

Така че тогава можете да създадете приложение, което поддържа връзка и използва LISTEN операция за идентифициране на необходимостта от извикване на REFRESH . Един хубав проект, който можете да използвате, за да тествате това, е pgsidekick, с този проект можете да използвате шел скрипт, за да правите LISTEN , така че можете да планирате REFRESH като:

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

Или използвайте pglater (също вътре в pgsidekick ), за да сте сигурни, че няма да извикате REFRESH много често. Например, можете да използвате следния тригер, за да го направите REFRESH , но в рамките на 1 минута (60 секунди):

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;
$$;

Така че няма да извика REFRESH за по-малко от 60 секунди, а също и ако NOTIFY много пъти за по-малко от 60 секунди, REFRESH ще се задейства само веднъж.

Съображения

Като опция за cron, тази също е добра само ако можете да използвате малко остарели данни, но това има предимството, че REFRESH се извиква само когато наистина е необходимо, така че имате по-малко режийни разходи, а също така данните се актуализират по-близо до когато е необходимо.

OBS:Все още не съм пробвал кодовете и примерите, така че ако някой открие грешка, печатна грешка или я опита и работи (или не), моля, уведомете ме.



  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 B-Tree

  2. Предоставяне на привилегии за бъдещи таблици в PostgreSQL?

  3. Как мога да получа списък с всички функции, съхранявани в базата данни на определена схема в PostgreSQL?

  4. как да съхранявате PostgreSQL jsonb с помощта на SpringBoot + JPA?

  5. Изпълнението на множество оператори с Postgresql чрез SQLAlchemy не запазва промените