本文首发于 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 里却依然存在依赖关系,因而,删除该表时,因为找不到最里层的依赖对象而报错。


欢送关注我的微信公众号【数据库内核】:分享支流开源数据库和存储引擎相干技术。

题目网址
GitHubhttps://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