PostgreSQL、MonetDB 和 MySQL 将外键添加到现有的 table
PostgreSQL, MonetDB and MySQL add foreign key to existing table
当我向已经有数据的 table 添加外键时,这些数据库管理系统各自做什么?
他们是否分析列的每个值以确认它是来自引用的 table 主键的值?
或者他们有什么其他的优化机制?如果是这样,那是什么机制?
我无法确认是否适用于 MonetDB,但在 PostgreSQL 和 MySQL(很可能也在 MonetDB 上)答案是肯定的,它们将检查每个值,如果密钥不正确,则会引发错误存在于引用的 table.
请注意,引用的列不必是引用的 table 的主键 - 您可以将任何列作为另一个 table.
的外键引用
是的,当然,不强制执行的约束是没有意义的。
您可以试试(这是针对 Postgres 的):
DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp ;
SET search_path=tmp;
CREATE TABLE one
( one_id SERIAL NOT NULL PRIMARY KEY
, name varchar
);
INSERT INTO one(name)
SELECT 'name_' || gs::text
FROM generate_series(1,10) gs ;
CREATE TABLE two
( two_id SERIAL NOT NULL PRIMARY KEY
, one_id INTEGER -- REFERENCES one(one_id)
);
INSERT INTO two(one_id)
SELECT one_id
FROM one ;
DELETE FROM one WHERE one_id%5=0;
ALTER TABLE two
ADD FOREIGN KEY (one_id) REFERENCES one(one_id)
;
\d one
\d two
结果:
NOTICE: drop cascades to 2 other objects
DETAIL: drop cascades to table tmp.one
drop cascades to table tmp.two
DROP SCHEMA
CREATE SCHEMA
SET
CREATE TABLE
INSERT 0 10
CREATE TABLE
INSERT 0 10
DELETE 2
ERROR: insert or update on table "two" violates foreign key constraint "two_one_id_fkey"
DETAIL: Key (one_id)=(5) is not present in table "one".
Table "tmp.one"
Column | Type | Modifiers
--------+-------------------+------------------------------------------------------
one_id | integer | not null default nextval('one_one_id_seq'::regclass)
name | character varying |
Indexes:
"one_pkey" PRIMARY KEY, btree (one_id)
Table "tmp.two"
Column | Type | Modifiers
--------+---------+------------------------------------------------------
two_id | integer | not null default nextval('two_two_id_seq'::regclass)
one_id | integer |
Indexes:
"two_pkey" PRIMARY KEY, btree (two_id)
错误消息与实际插入或更新时的错误消息相同。您可以看到引擎在遇到第一个冲突行时退出。
当我向已经有数据的 table 添加外键时,这些数据库管理系统各自做什么?
他们是否分析列的每个值以确认它是来自引用的 table 主键的值?
或者他们有什么其他的优化机制?如果是这样,那是什么机制?
我无法确认是否适用于 MonetDB,但在 PostgreSQL 和 MySQL(很可能也在 MonetDB 上)答案是肯定的,它们将检查每个值,如果密钥不正确,则会引发错误存在于引用的 table.
请注意,引用的列不必是引用的 table 的主键 - 您可以将任何列作为另一个 table.
的外键引用是的,当然,不强制执行的约束是没有意义的。 您可以试试(这是针对 Postgres 的):
DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp ;
SET search_path=tmp;
CREATE TABLE one
( one_id SERIAL NOT NULL PRIMARY KEY
, name varchar
);
INSERT INTO one(name)
SELECT 'name_' || gs::text
FROM generate_series(1,10) gs ;
CREATE TABLE two
( two_id SERIAL NOT NULL PRIMARY KEY
, one_id INTEGER -- REFERENCES one(one_id)
);
INSERT INTO two(one_id)
SELECT one_id
FROM one ;
DELETE FROM one WHERE one_id%5=0;
ALTER TABLE two
ADD FOREIGN KEY (one_id) REFERENCES one(one_id)
;
\d one
\d two
结果:
NOTICE: drop cascades to 2 other objects
DETAIL: drop cascades to table tmp.one
drop cascades to table tmp.two
DROP SCHEMA
CREATE SCHEMA
SET
CREATE TABLE
INSERT 0 10
CREATE TABLE
INSERT 0 10
DELETE 2
ERROR: insert or update on table "two" violates foreign key constraint "two_one_id_fkey"
DETAIL: Key (one_id)=(5) is not present in table "one".
Table "tmp.one"
Column | Type | Modifiers
--------+-------------------+------------------------------------------------------
one_id | integer | not null default nextval('one_one_id_seq'::regclass)
name | character varying |
Indexes:
"one_pkey" PRIMARY KEY, btree (one_id)
Table "tmp.two"
Column | Type | Modifiers
--------+---------+------------------------------------------------------
two_id | integer | not null default nextval('two_two_id_seq'::regclass)
one_id | integer |
Indexes:
"two_pkey" PRIMARY KEY, btree (two_id)
错误消息与实际插入或更新时的错误消息相同。您可以看到引擎在遇到第一个冲突行时退出。