Sto caricando un gruppo di dati in un database PostgresQL 9.3 e quindi voglio aggiornare tutte le viste materializzate che dipendono dalle tabelle aggiornate. C'è un modo per farlo automaticamente invece di passare attraverso ogni vista e rinfrescarli uno per uno? So che Oracle può farlo abbastanza facilmente ma non ho trovato nulla dopo aver letto la documentazione di PostgreSQL.Come aggiornare tutte le viste materializzate in Postgresql 9.3 in una sola volta?
risposta
Assomiglia attuale versione di PostgreSQL (9.3.1) non ha tale funzionalità, hanno dovuto scrivere la mia funzione invece:
CREATE OR REPLACE FUNCTION RefreshAllMaterializedViews(schema_arg TEXT DEFAULT 'public')
RETURNS INT AS $$
DECLARE
r RECORD;
BEGIN
RAISE NOTICE 'Refreshing materialized view in schema %', schema_arg;
FOR r IN SELECT matviewname FROM pg_matviews WHERE schemaname = schema_arg
LOOP
RAISE NOTICE 'Refreshing %.%', schema_arg, r.matviewname;
EXECUTE 'REFRESH MATERIALIZED VIEW ' || schema_arg || '.' || r.matviewname;
END LOOP;
RETURN 1;
END
$$ LANGUAGE plpgsql;
(su GitHub: https://github.com/sorokine/RefreshAllMaterializedViews)
Ora con il supporto della parola chiave ["CONCURRENTLY"] (https://wiki.postgresql.org/wiki/What%27s_new_in_PostgreSQL_9.4#REFRESH_MATERIALIZED_VIEW_CONCURRENTLY) in 9.4, sarebbe interessante per te utilizzarlo per impedire il blocco del tavolo? –
Voglio esaminarlo non appena ho messo le mani su 9.4 installazione. Penso che sarà un'aggiunta conveniente. – srk
Oggi ho inserito il codice nel ramo principale di https://github.com/sorokine/RefreshAllMaterializedViews che esegue aggiornamenti simultanei. – srk
stesso metodo, aggiunto il controllo standby
CREATE OR REPLACE FUNCTION RefreshAllMaterializedViews(schema_arg TEXT DEFAULT 'public')
RETURNS INT AS $$
DECLARE
r RECORD;
BEGIN
RAISE NOTICE 'Refreshing materialized view in schema %', schema_arg;
if pg_is_in_recovery() then
return 1;
else
FOR r IN SELECT matviewname FROM pg_matviews WHERE schemaname = schema_arg
LOOP
RAISE NOTICE 'Refreshing %.%', schema_arg, r.matviewname;
EXECUTE 'REFRESH MATERIALIZED VIEW ' || schema_arg || '.' || r.matviewname;
END LOOP;
end if;
RETURN 1;
END
$$ LANGUAGE plpgsql;
stesso metodo, aggiunta l'opzione per eseguirlo su tutti gli schemi, facoltativamente contemporaneamente.
CREATE OR REPLACE FUNCTION RefreshAllMaterializedViews(_schema TEXT DEFAULT '*', _concurrently BOOLEAN DEFAULT false)
RETURNS INT AS $$
DECLARE
r RECORD;
BEGIN
RAISE NOTICE 'Refreshing materialized view(s) in % %', CASE WHEN _schema = '*' THEN ' all schemas' ELSE 'schema "'|| _schema || '"' END, CASE WHEN _concurrently THEN 'concurrently' ELSE '' END;
IF pg_is_in_recovery() THEN
RETURN 0;
ELSE
FOR r IN SELECT schemaname, matviewname FROM pg_matviews WHERE schemaname = _schema OR _schema = '*'
LOOP
RAISE NOTICE 'Refreshing %.%', r.schemaname, r.matviewname;
EXECUTE 'REFRESH MATERIALIZED VIEW ' || CASE WHEN _concurrently THEN 'CONCURRENTLY ' ELSE '' END || '"' || r.schemaname || '"."' || r.matviewname || '"';
END LOOP;
END IF;
RETURN 1;
END
$$ LANGUAGE plpgsql;
Ho messo su GitHub: https://github.com/frankhommers/RefreshAllMaterializedViews
Il frammento di seguito utilizza REFRESH MATERIALIZED VIEW CONCURRENTLY
quando esiste un indice UNIQUE
per quella vista.
CREATE OR REPLACE FUNCTION public.refresh_materialized_views()
RETURNS void
AS
$BODY$
DECLARE
refresh_sql text;
BEGIN
WITH matviews AS (
SELECT t.oid,
relname AS view_name,
nspname AS schema_name
FROM pg_class t
JOIN pg_catalog.pg_namespace n ON n.oid = t.relnamespace
WHERE t.relkind = 'm'
AND nspname NOT LIKE 'pg-%'
), unique_indexes AS (
SELECT m.oid,
view_name,
schema_name
FROM pg_class i,
pg_index ix,
matviews m
WHERE ix.indisunique = true
AND ix.indexrelid = i.oid
AND ix.indrelid = m.oid
), refresh_concurrently AS (
SELECT 'REFRESH MATERIALIZED VIEW CONCURRENTLY ' || quote_ident(schema_name) || '.' || quote_ident(view_name) AS sql
FROM unique_indexes
), refresh AS (
SELECT 'REFRESH MATERIALIZED VIEW ' || quote_ident(schema_name) || '.' || quote_ident(view_name) AS sql
FROM matviews
WHERE oid != all (SELECT oid FROM unique_indexes)
), sql AS (
SELECT sql FROM refresh_concurrently
UNION ALL
SELECT sql FROM refresh
)
SELECT string_agg(sql, E';\n') || E';\n' FROM sql INTO refresh_sql;
EXECUTE refresh_sql;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
Questo frammento accetta un nome di schema per limitare i punti di vista che sono rinfrescati.
CREATE OR REPLACE FUNCTION public.refresh_materialized_views(_schema text)
RETURNS void
AS
$BODY$
DECLARE
refresh_sql text;
BEGIN
WITH matviews AS (
SELECT t.oid,
relname AS view_name,
nspname AS schema_name
FROM pg_class t
JOIN pg_catalog.pg_namespace n ON n.oid = t.relnamespace
WHERE t.relkind = 'm'
AND nspname NOT LIKE 'pg-%'
AND nspname = _schema
), unique_indexes AS (
SELECT m.oid,
view_name,
schema_name
FROM pg_class i,
pg_index ix,
matviews m
WHERE ix.indisunique = true
AND ix.indexrelid = i.oid
AND ix.indrelid = m.oid
), refresh_concurrently AS (
SELECT 'REFRESH MATERIALIZED VIEW CONCURRENTLY ' || quote_ident(schema_name) || '.' || quote_ident(view_name) AS sql
FROM unique_indexes
), refresh AS (
SELECT 'REFRESH MATERIALIZED VIEW ' || quote_ident(schema_name) || '.' || quote_ident(view_name) AS sql
FROM matviews
WHERE oid != all (SELECT oid FROM unique_indexes)
), sql AS (
SELECT sql FROM refresh_concurrently
UNION ALL
SELECT sql FROM refresh
)
SELECT string_agg(sql, E';\n') || E';\n' FROM sql INTO refresh_sql;
EXECUTE refresh_sql;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
Controllare pg_matviews, selezionare tutte le visualizzazioni necessarie e eseguire un aggiornamento. Potresti scrivere una funzione per questo. –
sembra come scrivere la mia funzione è l'unica opzione con la versione corrente – srk