5.15. 依赖跟踪 #

当您创建包含许多具有外键约束、视图、触发器、函数等的表的复杂数据库结构时,您会隐式地创建对象之间依赖关系的集合。例如,具有外键约束的表依赖于它所引用的表。

为了确保整个数据库结构的完整性,PostgreSQL 会确保您不能删除其他对象仍然依赖的对象。例如,尝试删除我们在第 5.5.5 节中考虑过的 products 表,而 orders 表依赖于它,将会导致如下错误消息:

DROP TABLE products;

ERROR:  cannot drop table products because other objects depend on it
DETAIL:  constraint orders_product_no_fkey on table orders depends on table products
HINT:  Use DROP ... CASCADE to drop the dependent objects too.

错误消息包含一个有用的提示:如果您不想逐个删除所有依赖对象,您可以运行:

DROP TABLE products CASCADE;

这样可以删除所有依赖对象,以及依赖于它们的所有对象,进行递归删除。在这种情况下,它不会删除 orders 表,只删除外键约束。它在此停止,因为没有对象依赖于外键约束。(如果您想检查 DROP ... CASCADE 会做什么,请在不带 CASCADE 的情况下运行 DROP 并阅读 DETAIL 输出。)

PostgreSQL 中几乎所有的 DROP 命令都支持指定 CASCADE。当然,可能的依赖关系的性质随对象的类型而变化。您也可以使用 RESTRICT 而不是 CASCADE 来获得默认行为,即阻止删除任何其他对象依赖的对象。

注意

根据 SQL 标准,在 DROP 命令中指定 RESTRICT 或 CASCADE 是必需的。实际上没有数据库系统强制执行此规则,但默认行为是 RESTRICT 还是 CASCADE 在不同系统之间是不同的。

如果 DROP 命令列出了多个对象,则仅当存在指定组之外的依赖关系时才需要 CASCADE。例如,当说 DROP TABLE tab1, tab2 时,如果存在一个引用 tab1 并从 tab2 来的外键,这并不意味着需要 CASCADE 才能成功。

对于主体定义为字符串字面量的用户定义函数或过程,PostgreSQL 会跟踪与函数外部可见属性(如其参数和结果类型)相关的依赖关系,但**不**会跟踪只能通过检查函数主体来识别的依赖关系。例如,考虑以下情况:

CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow',
                             'green', 'blue', 'purple');

CREATE TABLE my_colors (color rainbow, note text);

CREATE FUNCTION get_color_note (rainbow) RETURNS text AS
  'SELECT note FROM my_colors WHERE color = $1'
  LANGUAGE SQL;

(有关 SQL 语言函数,请参阅第 36.5 节。) PostgreSQL 会知道 get_color_note 函数依赖于 rainbow 类型:删除该类型将强制删除该函数,因为其参数类型将不再被定义。但是 PostgreSQL 不会将 get_color_note 视为依赖于 my_colors 表,因此如果删除该表,将不会删除该函数。虽然这种方法有缺点,但也有优点。如果表丢失,该函数在某种意义上仍然是有效的,尽管执行它会导致错误;创建一个同名的新表将允许函数再次工作。

另一方面,对于主体是用 SQL 标准样式编写的 SQL 语言函数或过程,主体在函数定义时被解析,并且所有解析器识别的依赖关系都会被存储。因此,如果我们这样编写上面的函数:

CREATE FUNCTION get_color_note (rainbow) RETURNS text
BEGIN ATOMIC
  SELECT note FROM my_colors WHERE color = $1;
END;

那么函数对 my_colors 表的依赖关系将是已知的,并且会被 DROP 强制执行。