本文首发于 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 1
postgres=# 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 是束缚的 OID
postgres=#
之所以呈现该报错,是因为手动把束缚对象删除了,但在 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 |