本文首发于 2015-11-04 15:28:08
前言
本文成文较早,依赖的是 PostgreSQL 9.3 版本,后续内核版本可能不兼容,但外围原理是相通的,可做参考。
表构造
pg_depend
pg_depend 是 postgres 的一张零碎表,用来记录数据库对象之间的依赖关系,除了常见的主外键,还有其余一些外部依赖关系,能够通过这个零碎表出现进去。
postgres=# \d+ pg_depend Table "pg_catalog.pg_depend" Column | Type | Modifiers | Storage | Stats target | Description-------------+---------+-----------+---------+--------------+------------- classid | oid | not null | plain | | 零碎OID objid | oid | not null | plain | | 对象OID objsubid | integer | not null | plain | | refclassid | oid | not null | plain | | 援用零碎OID refobjid | oid | not null | plain | | 援用对象ID refobjsubid | integer | not null | plain | | deptype | "char" | not null | plain | | pg_depend类型Indexes: "pg_depend_depender_index" btree (classid, objid, objsubid) "pg_depend_reference_index" btree (refclassid, refobjid, refobjsubid)Has OIDs: no
OID 是 Object Identifier 的缩写,是对象 ID 的意思,因为是无符号的4字节类型,示意范畴不够大,所以个别不必做主键应用,仅用在零碎外部,比方零碎表等利用。能够与一些整型数字进行转换。与之相干的零碎参数是 default_with_oids
,默认是 off 。
pg_depend.deptype
字段自 9.1 版本之后多了一个 extension 的类型,目前类型有:
DEPENDENCY_NORMAL (n)
:一般的依赖对象,如表与schema的关系。DEPENDENCY_AUTO (a)
:主动的依赖对象,如主键束缚。DEPENDENCY_INTERNAL (i)
:外部的依赖对象,通常是对象自身。DEPENDENCY_EXTENSION (e)
:9.1新增的的扩大依赖。DEPENDENCY_PIN (p)
:零碎内置的依赖。
pg_constraint
postgres=# \d pg_constraint Table "pg_catalog.pg_constraint" Column | Type | Modifiers ---------------+--------------+----------- conname | name | not null -- 束缚名 connamespace | oid | not null -- 束缚所在命名空间的OID contype | "char" | not null -- 束缚类型 condeferrable | boolean | not null -- 束缚是否能够推延 condeferred | boolean | not null -- 缺省状况下,束缚是否能够推延 convalidated | boolean | not null -- 束缚是否通过验证 conrelid | oid | not null -- 束缚所在的表的OID contypid | oid | not null -- 束缚所在的域的OID conindid | oid | not null -- 如果是惟一、主键、外键或排除束缚,则为反对这个束缚的索引;否则为0 confrelid | oid | not null -- 如果是外键,则为参考的表;否则为 0 confupdtype | "char" | not null -- 外键更新操作代码 confdeltype | "char" | not null -- 外键删除操作代码 confmatchtype | "char" | not null -- 外键匹配类型 conislocal | boolean | not null coninhcount | integer | not null -- 束缚间接继承先人的数量 connoinherit | boolean | not null conkey | smallint[] | -- 如果是表束缚(蕴含外键,然而不蕴含束缚触发器),则是束缚字段的列表 confkey | smallint[] | -- 如果是一个外键,是参考的字段的列表 conpfeqop | oid[] | -- 如果是一个外键,是PK = FK比拟的相等操作符的列表 conppeqop | oid[] | -- 如果是一个外键,是PK = PK比拟的相等操作符的列表 conffeqop | oid[] | -- 如果是一个外键,是FK = FK比拟的相等操作符的列表 conexclop | oid[] | -- 如果是一个排除束缚,是每个字段排除操作符的列表 conbin | pg_node_tree | -- 如果是一个查看束缚,那就是其表达式的外部模式 consrc | text | -- 如果是查看束缚,则是表达式的人类可读模式Indexes: "pg_constraint_oid_index" UNIQUE, btree (oid) "pg_constraint_conname_nsp_index" btree (conname, connamespace) "pg_constraint_conrelid_index" btree (conrelid) "pg_constraint_contypid_index" btree (contypid)
查问依赖关系的 SQL
如下 SQL 能够列出零碎和用户对象的各种依赖关系:
SELECT classid::regclass AS "depender object class", CASE classid WHEN 'pg_class'::regclass THEN objid::regclass::text WHEN 'pg_type'::regclass THEN objid::regtype::text WHEN 'pg_proc'::regclass THEN objid::regprocedure::text ELSE objid::text END AS "depender object identity", objsubid, refclassid::regclass AS "referenced object class", CASE refclassid WHEN 'pg_class'::regclass THEN refobjid::regclass::text WHEN 'pg_type'::regclass THEN refobjid::regtype::text WHEN 'pg_proc'::regclass THEN refobjid::regprocedure::text ELSE refobjid::text END AS "referenced object identity", refobjsubid, CASE deptype WHEN 'p' THEN 'pinned' WHEN 'i' THEN 'internal' WHEN 'a' THEN 'automatic' WHEN 'n' THEN 'normal' END AS "dependency type"FROM pg_catalog.pg_depend WHERE (objid >= 16384 OR refobjid >= 16384);
我通常喜爱在 where 前面加个条件 and deptype <>'i'
,以排除 internal 依赖。
示例
创立一张表:
postgres=# create table tbl_parent(id int);CREATE TABLE
执行查问依赖关系的 SQL:
postgres=# 执行下面的SQL; depender object class | depender object identity | objsubid | referenced object class | referenced object identity | refobjsubid | dependency type-----------------------+--------------------------+----------+-------------------------+------------- pg_class | tbl_parent | 0 | pg_namespace | 2200 | 0 | normal(1 row)
看起来只是建了个表,没有束缚,实际上该表是建设在 schema 上面的,因而只依赖于 schema 。
增加主键束缚:
postgres=# alter table tbl_parent add primary key(id);ALTER TABLE depender object class | depender object identity | objsubid | referenced object class | referenced object identity | refobjsubid | dependency type-----------------------+--------------------------+----------+-------------------------+------- pg_class | tbl_parent | 0 | pg_namespace | 2200 | 0 | normal pg_constraint | 16469 | 0 | pg_class | tbl_parent | 1 | automatic(2 rows)
束缚类型变为了automatic
,表明这个主键束缚是依赖于表上的,是主动模式,详细信息能够在零碎表pg_constrant
外面查问。
失常状况下用户删除有依赖关系的对象时,会提醒须要先删除依赖的对象。然而如果通过零碎表删除有依赖关系的对象时,若操作有误,就会导致异样。例如:上面的操作就会导致报错cache lookup failed for constraint
:
postgres=# select oid,conname,connamespace,contype from pg_constraint where conname like 'tbl_parent%'; oid | conname | connamespace | contype-------+-----------------+--------------+--------- 16469 | tbl_parent_pkey | 2200 | p(1 row) postgres=# delete from pg_constraint where conname like 'tbl_parent%';DELETE 1postgres=# select oid,conname,connamespace,contype from pg_constraint where conname like 'tbl_parent%'; oid | conname | connamespace | contype-----+---------+--------------+---------(0 rows) postgres=# drop table tbl_parent;ERROR: cache lookup failed for constraint 16469 --16496是束缚的OIDpostgres=#
之所以呈现该报错,是因为手动把束缚对象删除了,但在 pg_depend 里却依然存在依赖关系,因而,删除该表时,因为找不到最里层的依赖对象而报错。
欢送关注我的微信公众号【数据库内核】:分享支流开源数据库和存储引擎相干技术。
题目 | 网址 |
---|---|
GitHub | https://dbkernel.github.io |
知乎 | https://www.zhihu.com/people/... |
思否(SegmentFault) | https://segmentfault.com/u/db... |
掘金 | https://juejin.im/user/5e9d3e... |
开源中国(oschina) | https://my.oschina.net/dbkernel |
博客园(cnblogs) | https://www.cnblogs.com/dbkernel |