乐趣区

关于postgresql:特性介绍-PostgreSQL-的依赖约束详解-系统表-pgdepend-pgconstraint

本文首发于 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
退出移动版