数据库内部:实现外键约束

时间:2015-03-15 19:25:20

标签: database postgresql database-design foreign-keys

如何在PostgreSQL中实现外键?

我注意到在创建外键时涉及很多哈希,所以我想在引用主键列的外键列上创建基于哈希的索引。如果是这样(例如,当我们想要从引用的表中删除一行 - 这一行带有主键或所谓的主表)时,我们可以很容易地检查引用表中的行是否实际被引用。更重要的是,DBMS可能要求在引用的主键列上至少有一个B +树索引,因为当我们想要将新行插入引用表时,我们可以轻松检查是否存在具有所需主键值的行在引用的表中。一些消息来源声称触发器用于确保外键约束。

2 个答案:

答案 0 :(得分:1)

在Postgres中,主表中引用的列需要具有UNIQUEPRIMARY KEY约束。 Per documentation:

  

引用的列必须是不可延迟的唯一列   或引用表中的主键约束。

目前总是使用btree索引实现这两个目标。因此总是引用列上的btree索引:

根本不需要索引引用列。如果主表中的行永远不会更新或删除,这可能就足够了。否则,引用列也应该被索引,但系统不强制执行。这只是性能优化,而不是数据完整性。

FK约束本身的实际实现是系统目录pg_constraint中的一个条目,一个特殊的内部触发器和pg_depend中的另一个条目。

答案 1 :(得分:0)

我检查过,确实,PostgreSQL没有为外键创建索引(使用此查询:https://stackoverflow.com/a/25596855/1245175)。

另一方面,为外键创建了一些触发器:

test=# SELECT tgname AS trigger_name
  FROM pg_trigger
 WHERE tgname !~ '^pg_';
 trigger_name
--------------
(0 rows)

test=# ALTER TABLE LINEITEM ADD CONSTRAINT LINEITEM_FK1 FOREIGN KEY (L_ORDERKEY)  REFERENCES ORDERS;
ALTER TABLE
test=# SELECT tgname AS trigger_name                                                               
  FROM pg_trigger
 WHERE tgname !~ '^pg_';
         trigger_name        
------------------------------
 RI_ConstraintTrigger_a_16419
 RI_ConstraintTrigger_a_16420
 RI_ConstraintTrigger_c_16421
 RI_ConstraintTrigger_c_16422

所以,我想在PostgreSQL中创建外键时,会为引用的表创建一个哈希映射,然后对引用表的每一行执行探测。

有趣的是,MonetDB为主键和外键创建了不同类型的索引(可能分别是join-index和hash-index)。

sql>select * from sys.idxs;
+------+----------+------+-------------+
| id   | table_id | type | name        |
+======+==========+======+=============+
| 6467 |     6446 |    0 | orders_pk   |
| 6470 |     6464 |    1 | lineitem_fk |
+------+----------+------+-------------+
2 tuples (3.921ms)

除此之外,Oracle使用索引强制执行主键约束,默认情况下它不会为外键创建任何索引,但是,有一些外键索引提示:https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:292016138754