- 这和创建三个独立的外键是一样的吗?
不是的。请考虑以下内容。
首先,把它看作(id,id,id)并没有实际意义,而是应该看作(id1,id2,id3)。因为一个元组(id,id,id)相比于只有在id
上建立单列索引没有任何优势。因此,下面的模式图显示了这一点。
create schema FKtest001;
use FKtest001;
create table user
( id int auto_increment primary key,
fullname varchar(100) not null,
id1 int not null,
id2 int not null,
id3 int not null,
index `idkUserTuple` (id1,id2,id3)
);
create table device
( id int auto_increment primary key,
something varchar(100) not null,
user_created_id int not null,
user_updated_id int not null,
user_deleted_id int not null,
foreign key `fk_device_user` (`user_created_id` , `user_updated_id` , `user_deleted_id`)
REFERENCES `user` (`id1` , `id2` , `id3`)
);
show create table device;
CREATE TABLE `device` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`something` varchar(100) NOT NULL,
`user_created_id` int(11) NOT NULL,
`user_updated_id` int(11) NOT NULL,
`user_deleted_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `fk_device_user` (`user_created_id`,`user_updated_id`,`user_deleted_id`),
CONSTRAINT `device_ibfk_1` FOREIGN KEY (`user_created_id`, `user_updated_id`, `user_deleted_id`) REFERENCES `user` (`id1`, `id2`, `id3`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
show indexes from device;
drop table device;
drop table user;
create table user
( id int auto_increment primary key,
fullname varchar(100) not null,
id1 int not null,
id2 int not null,
id3 int not null,
index `idkUser1` (id1),
index `idkUser2` (id2),
index `idkUser3` (id3)
);
create table device
( id int auto_increment primary key,
something varchar(100) not null,
user_created_id int not null,
user_updated_id int not null,
user_deleted_id int not null,
foreign key `fk_device_user1` (`user_created_id`)
REFERENCES `user` (`id1`),
foreign key `fk_device_user2` (`user_updated_id`)
REFERENCES `user` (`id2`),
foreign key `fk_device_user3` (`user_deleted_id`)
REFERENCES `user` (`id3`)
);
show create table device;
CREATE TABLE `device` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`something` varchar(100) NOT NULL,
`user_created_id` int(11) NOT NULL,
`user_updated_id` int(11) NOT NULL,
`user_deleted_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `fk_device_user1` (`user_created_id`),
KEY `fk_device_user2` (`user_updated_id`),
KEY `fk_device_user3` (`user_deleted_id`),
CONSTRAINT `device_ibfk_1` FOREIGN KEY (`user_created_id`) REFERENCES `user` (`id1`),
CONSTRAINT `device_ibfk_2` FOREIGN KEY (`user_updated_id`) REFERENCES `user` (`id2`),
CONSTRAINT `device_ibfk_3` FOREIGN KEY (`user_deleted_id`) REFERENCES `user` (`id3`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
show indexes from device;
有两个部分。在顶部,
show indexes from device
将显示维护的2个索引之间的差异。在底部,维护了4个索引。如果由于某种原因,顶部部分的索引元组对系统有用,则该元组方法肯定是正确的选择。
原因如下。这个元组作为一个组存在。将其视为具有组意义的集合实例。与仅存在各个部分不同,存在差异。不是用户存在,而是存在一个用户行,该行将该元组作为存在。
2.使用其中一个的利弊有哪些?
上一段描述了优点:在
user
表中作为元组实际分组的存在。
它们是苹果和橙子,用于不同的目的。
3.这的确是什么情况? (主要问题)
一个用例需要将元组作为组的存在,而不是单个项目的存在。用于所谓的组合。特别是组合FK。查看我的答案
Here 作为一个案例。
简而言之,当您想执行需要对其他实体的组合级别(分组)进行参考完整性(RI)的特殊难以想象的解决方案时,可以使用它。许多人认为无法完成,因此他们首先考虑
TRIGGER
执行或前端执行。幸运的是,这些用例可以通过FK Composites实现,从而使RI留在应该存在的db级别(永远不会在前端)。
补充说明
OP要求比上面的链接更好的实际示例。
考虑以下模式:
CREATE SCHEMA testRealLifeTuple;
USE testRealLifeTuple;
CREATE TABLE contacts
( id INT AUTO_INCREMENT PRIMARY KEY,
fullname VARCHAR(100) NOT NULL
);
CREATE TABLE tupleHolder
(
id INT AUTO_INCREMENT PRIMARY KEY,
CEO INT NOT NULL,
CFO INT NOT NULL,
CIO INT NOT NULL,
creditWorthiness INT NOT NULL,
UNIQUE INDEX `idk_ContactTuple` (CEO,CFO,CIO),
FOREIGN KEY `fk_th_ceo` (`CEO`) REFERENCES `contacts` (`id`),
FOREIGN KEY `fk_th_cfo` (`CFO`) REFERENCES `contacts` (`id`),
FOREIGN KEY `fk_th_cio` (`CIO`) REFERENCES `contacts` (`id`)
);
CREATE TABLE device
(
id INT AUTO_INCREMENT PRIMARY KEY,
something VARCHAR(100) NOT NULL,
CEO INT NOT NULL,
CFO INT NOT NULL,
CIO INT NOT NULL,
FOREIGN KEY `fk_device_2_tuple` (`CEO` , `CFO` , `CIO`)
REFERENCES `tupleHolder` (`CEO` , `CFO` , `CIO`)
);
DROP SCHEMA testRealLifeTuple;
这个架构的亮点在于
tupleHolder
表中的
UNIQUE KEY
,
device
中的 FK,
GRANT
限制(未显示授权),以及设备受到防篡改保护,因为如上所述:
- GRANTS
- 必须遵守 FK,因此不能对
tupleHolder
进行编辑。
如果
tupleHolder
被篡改(3个
contacts
的id),则将违反 FK。
换句话说,这完全不同于设备基于设备中单个列(称为 [device.badIdea INT])具有的 FK,该列会回溯到 tupleHolder.id。
而且,正如先前提到的那样,这与仅仅拥有
contacts
不同。相反,重要的是
contacts
的组成存在,即元组。 在我们的案例中,元组已经通过审核,并且具有信用评级,在购买设备后,其中的 id 不能被更改,除非具有足够的 GRANTS 权限。即使有,FK 也仍然存在。
这可能需要15分钟才能理解清楚,但是差别是巨大的。
希望这有所帮助。