多数のデータを PostgresQL 9.3 データベースにロードしてから、更新されたテーブルに依存するすべてのマテリアライズド ビューを更新したいと考えています。各ビューを確認して 1 つずつ更新する代わりに、自動的に行う方法はありますか? Oracle がそれをかなり簡単に実行できることは知っていますが、PostgreSQL のドキュメントをくまなく調べても何も見つかりませんでした。
質問する
12378 次
5 に答える
8
マテリアライズドビューが互いに依存していない場合、上記の回答は正常に機能します。そうでない場合は、マテリアライズド ビューを更新する順序が重要です (つまり、他のマテリアライズド ビューを更新する前に、他のマテリアライズド ビューに依存しないマテリアライズド ビューを更新する必要があります)。以下のコードは、マテリアライズド ビューの順序付きリストを生成して、正しい順序で更新できるようにします。
CREATE OR REPLACE VIEW mat_view_dependencies AS
WITH RECURSIVE s(start_schemaname,start_mvname,schemaname,mvname,relkind,
mvoid,depth) AS (
-- List of mat views -- with no dependencies
SELECT n.nspname AS start_schemaname, c.relname AS start_mvname,
n.nspname AS schemaname, c.relname AS mvname, c.relkind,
c.oid AS mvoid, 0 AS depth
FROM pg_class c JOIN pg_namespace n ON c.relnamespace=n.oid
WHERE c.relkind='m'
UNION
-- Recursively find all things depending on previous level
SELECT s.start_schemaname, s.start_mvname,
n.nspname AS schemaname, c.relname AS mvname,
c.relkind,
c.oid AS mvoid, depth+1 AS depth
FROM s
JOIN pg_depend d ON s.mvoid=d.refobjid
JOIN pg_rewrite r ON d.objid=r.oid
JOIN pg_class c ON r.ev_class=c.oid AND (c.relkind IN ('m','v'))
JOIN pg_namespace n ON n.oid=c.relnamespace
WHERE s.mvoid <> c.oid -- exclude the current MV which always depends on itself
)
SELECT * FROM s;
CREATE OR REPLACE VIEW mat_view_refresh_order AS
WITH b AS (
-- Select the highest depth of each mat view name
SELECT DISTINCT ON (schemaname,mvname) schemaname, mvname, depth
FROM mat_view_dependencies
WHERE relkind='m'
ORDER BY schemaname, mvname, depth DESC
)
-- Reorder appropriately
SELECT schemaname, mvname, depth AS refresh_order
FROM b
ORDER BY depth, schemaname, mvname
;
これを使用しpsql
て、次のようにすべてのビューを適切な順序で更新できます。
WITH a AS (
SELECT 'REFRESH MATERIALIZED VIEW "' || schemaname || '"."' || mvname || '";' AS r
FROM mat_view_refresh_order
ORDER BY refresh_order
)
SELECT string_agg(r,E'\n') AS script FROM a \gset
\echo :script
:script
この最後の部分は、代わりに、以前のソリューションで行われたように関数に変換できます。
于 2018-07-17T13:21:52.963 に答える
2
同じ方法で、オプションで同時にすべてのスキーマで実行するオプションが追加されました。
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;
GitHub にも置いています: https://github.com/frankhommers/RefreshAllMaterializedViews
于 2015-12-04T10:02:53.937 に答える
1
同じ方法、待機チェックを追加
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;
于 2015-03-31T14:53:43.807 に答える