PostgreSQL 使用递归SQL 找出数据库对象之间的依赖关系 - 例如视图依赖
2023-06-13 09:17:40 时间
背景:
在数据库中对象与对象之间存在一定的依赖关系,例如继承表之间的依赖,视图与基表的依赖,主外键的依赖,序列的依赖等等。
在删除对象时,数据库也会先检测依赖,如果有依赖,会报错,需要使用cascade删除。
另外一方面,如果需要重建表,使用重命名的方式是有一定风险的,例如依赖关系没有迁移,仅仅迁移了表是不够的。
所以迁移,通常使用的是增量迁移数据,同时使用替换filenode的方式更加靠谱,依赖关系不变。
本文将介绍一下如何查找依赖关系。
创建2个view,用于测试
在当前schema下创建2个视图
=# create view v1 as select * from pglog;
=# create view v2 as select * from v1;
在其它schema下也创建一个视图
=# create schema sm1;
=# create view sm1.v1 as select * from pglog limit 10;
创建一个解析函数,得到依赖的OID
-- 注意下search_path,下面建的function都是只能在指定的search_path下访问到。
set search_path='public';
create or replace function get_dep_oids(oid) returns oid[] as $$
declare
res oid[];
begin
select array_agg(unnest::oid) into res from
(
select unnest(regexp_matches(ev_action::text,':relid (\d+)', 'g')) from pg_rewrite where ev_class = $1
union
select unnest(regexp_matches(ev_action::text,':resorigtbl (\d+)','g')) from pg_rewrite where ev_class = $1
EXCEPT
select oid::text from pg_class where oid=$1
) t;
return res;
end;
$$ language plpgsql strict;
=# select * from get_dep_oids('v1'::regclass);
get_dep_oids
──────────────
{24971}
(1 row)
14:41:19 db: postgres@postgres, pid:54661
=# select * from get_dep_oids('v2'::regclass);
get_dep_oids
──────────────
{24975}
(1 row)
=# select * from get_dep_oids('sm1.v1'::regclass);
get_dep_oids
──────────────
{24971}
(1 row)
再创建一个函数,递归的得到依赖的对象。
create or replace function recursive_get_deps(IN tbl oid, OUT oid oid, OUT relkind "char", OUT nspname name, OUT relname name, OUT deps oid[], OUT ori_oid oid, OUT ori_relkind "char", OUT ori_nspname name, OUT ori_relname name ) returns setof record as
$$
declare
begin
return query
with recursive a as (
select * from (
select t1.oid,t1.relkind,t2.nspname,t1.relname,get_dep_oids(t1.oid) deps,(select t1.oid from pg_class t1,pg_namespace t2 where t1.relnamespace=t2.oid and t1.oid=tbl) as ori_oid from pg_class t1, pg_namespace t2 where t1.relnamespace=t2.oid and t1.relkind in ('m','v')
) t where t.ori_oid = any(t.deps)
union
select * from (
select t1.oid,t1.relkind,t2.nspname,t1.relname,get_dep_oids(t1.oid) deps, a.oid as ori_oid from pg_class t1,pg_namespace t2,a where t1.relnamespace=t2.oid and t1.relkind in ('m','v')
) t where t.ori_oid = any(t.deps)
)
select a.oid,a.relkind,a.nspname,a.relname,a.deps,a.ori_oid,b.relkind ori_relkind, c.nspname ori_nspname,b.relname ori_relname from a,pg_class b,pg_namespace c where a.ori_oid=b.oid and b.relnamespace=c.oid order by a.nspname,a.relkind,a.relname;
end;
$$ language plpgsql strict;
验证效果
=# select * from recursive_get_deps('pglog'::regclass);
oid │ relkind │ nspname │ relname │ deps │ ori_oid │ ori_relkind │ ori_nspname │ ori_relname
───────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────────┼─────────────┼─────────────
24975 │ v │ public │ v1 │ {24971} │ 24971 │ f │ public │ pglog
24982 │ v │ public │ v2 │ {24975} │ 24975 │ v │ public │ v1
24987 │ v │ sm1 │ v1 │ {24971} │ 24971 │ f │ public │ pglog
(3 rows)
可以看到依赖到pglog表的有3个视图,分别是public schema下的 v1 和 v2 视图、sm1 schema下的v1 视图。
获取视图的定义
14:41:21 db: postgres@postgres, pid:54661
=# select * from pg_get_viewdef('v1',false);
pg_get_viewdef
───────────────────────────────────
SELECT pglog.log_time, ↵
pglog.user_name, ↵
pglog.database_name, ↵
pglog.process_id, ↵
pglog.connection_from, ↵
pglog.session_id, ↵
pglog.session_line_num, ↵
pglog.command_tag, ↵
pglog.session_start_time, ↵
pglog.virtual_transaction_id,↵
pglog.transaction_id, ↵
pglog.error_severity, ↵
pglog.sql_state_code, ↵
pglog.message, ↵
pglog.detail, ↵
pglog.hint, ↵
pglog.internal_query, ↵
pglog.internal_query_pos, ↵
pglog.context, ↵
pglog.query, ↵
pglog.query_pos, ↵
pglog.location, ↵
pglog.application_name ↵
FROM pglog;
(1 row)
=# select * from pg_get_viewdef('v2',false);
pg_get_viewdef
────────────────────────────────
SELECT v1.log_time, ↵
v1.user_name, ↵
v1.database_name, ↵
v1.process_id, ↵
v1.connection_from, ↵
v1.session_id, ↵
v1.session_line_num, ↵
v1.command_tag, ↵
v1.session_start_time, ↵
v1.virtual_transaction_id,↵
v1.transaction_id, ↵
v1.error_severity, ↵
v1.sql_state_code, ↵
v1.message, ↵
v1.detail, ↵
v1.hint, ↵
v1.internal_query, ↵
v1.internal_query_pos, ↵
v1.context, ↵
v1.query, ↵
v1.query_pos, ↵
v1.location, ↵
v1.application_name ↵
FROM v1;
(1 row)
=# select * from pg_get_viewdef('sm1.v1',false);
pg_get_viewdef
───────────────────────────────────
SELECT pglog.log_time, ↵
pglog.user_name, ↵
pglog.database_name, ↵
pglog.process_id, ↵
pglog.connection_from, ↵
pglog.session_id, ↵
pglog.session_line_num, ↵
pglog.command_tag, ↵
pglog.session_start_time, ↵
pglog.virtual_transaction_id,↵
pglog.transaction_id, ↵
pglog.error_severity, ↵
pglog.sql_state_code, ↵
pglog.message, ↵
pglog.detail, ↵
pglog.hint, ↵
pglog.internal_query, ↵
pglog.internal_query_pos, ↵
pglog.context, ↵
pglog.query, ↵
pglog.query_pos, ↵
pglog.location, ↵
pglog.application_name ↵
FROM pglog ↵
LIMIT 10;
(1 row)
相关文章
- Diesel框架对于数据库的使用和实战,在PostgreSQL的基础上的使用【Diesel】
- postgresql数据库基础 之 实现时间范围查询
- PostgreSQL 数据库基础 动态统计某一列的某一值出现的次数SQL
- PostgreSQL用户、数据库及表的管理、操作与授权方式
- 用PostgreSQL数据库做地理位置app应用
- postgresql 清空数据表 truncate详解数据库
- 优化实现PostgreSQL缓存优化,更高性能!(postgresql缓存)
- 使用SQL连接Oracle数据库(sql连接oracle)
- 空间数据管理:MySQL数据库之美(空间mysql数据库)
- 请聆听:Postgresql发音(postgresql发音)
- pl/sql探索Oracle数据库:SQL PL/SQL(oraclesql)
- 学习PostgreSQL:踏上数据库运维之路(postgresql使用教程)
- PostgreSQL:未来数据库发展的光明前景(postgresql前景)
- 探索PostgreSQL客户端工具,优化数据库管理(postgresql客户端工具)
- PostgreSQL 接口:连接数据库的必备工具(postgresql接口)
- Mysql与SQL:两个不同的数据库技术(mysql与sql的区别)
- 深入了解PostgreSQL数据类型:解决您的数据库存储难题(postgresql数据类型)
- SQL党进阶必备:轻松转换Oracle数据库教程(sql转oracle)
- 数据库导入SQL脚本,使用MSSQL数据库快速实现数据迁移(sql文件导入mssql)
- Postgresql操作指南:极致生产力体系构建(postgresql操作)
- 修复PostgreSQL:解决数据库难题(postgresql问题)
- 大数据应用探索PostgreSQL在中国大数据应用中的可能性(postgresql中国)
- 深入剖析:PostgreSQL vs. Microsoft SQL Server(pg数据库对比mssql)
- 深入浅出:精通Oracle数据库SQL语句(oracle数据库sql语句)
- 深入了解 PostgreSQL 数据库结构(postgresql结构)
- PostgreSQL登录:实现无缝连接(postgresql登录)
- MySQL中SQL窗口教程,轻松了解查询修改删除数据库表中数据的基本操作(mysql 中sql窗口)
- Oracle数据库中修改值的SQL方法简介(oracle修改值sql)