使用MySQL外键引用多列

时间:2016-09-12 11:52:07

标签: mysql foreign-keys composite

我偶然发现了MySQL外键引用多列的可能性。我想知道如下所示的多列外键的主要用途是什么

ALTER TABLE `device` 
ADD CONSTRAINT `fk_device_user`
  FOREIGN KEY (`user_created_id` , `user_updated_id` , `user_deleted_id`)
  REFERENCES `user` (`id` , `id` , `id`)
  ON DELETE NO ACTION
  ON UPDATE NO ACTION;

我的问题是

  1. 是否与创建三个独立的外键相同?
  2. 是否有使用其中一种的优点/缺点?
  3. 这是什么用例?(主要问题)

1 个答案:

答案 0 :(得分:3)

  1. 是否与创建三个独立的外键相同?
  2. 没有。请考虑以下事项。

    首先,将它想象为(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; -- shows 2 indexes (a PK, and composite BTREE)
    -- FOCUS heavily on the `Seq_in_index` column for the above
    
    -- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    
    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; -- shows 4 indexes (a PK, and 3 indiv FK indexes)
    -- FOCUS heavily on the `Seq_in_index` column for the above
    

    那里有2个部分。 show indexes from device将在顶部显示维护的2个索引的差异。在底部,保留了4个索引。如果由于某种原因,顶部的索引元组对系统有用,那么那个元组方法肯定是可行的方法。

    原因如下。元组作为一个组存在。可以将其视为具有集体意义的集合的实例。将其与单个零件的存在进行比较,并且存在差异。并不是用户存在,而是有一个用户行将该元组存在。

    1. 是否有使用其中一种的优点/缺点?
    2. 上面的段落中描述了专业人员:作为元组存在于user表中的实际分组。

      它们是苹果和橙子,用于不同的目的。

      1. 具体用例是什么? (主要问题)
      2. 用例将需要将元组作为一个组存在,而不是存在单个项。它用于所谓的合成。特别是合成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
            -- etc
        );
        
        CREATE TABLE tupleHolder
        (   -- a tuple representing a necessary Three-some validation
            -- and vetting to get financing
            --
            -- If you can't vett these 3, you can't have my supercomputer financed
            --
            id INT AUTO_INCREMENT PRIMARY KEY,
            CEO INT NOT NULL,   -- Chief Executive Officer
            CFO INT NOT NULL,   -- Chief Financial Officer
            CIO INT NOT NULL,   -- Chief Geek
            creditWorthiness INT NOT NULL, -- 1 to 100. 100 is best
        
            -- the unique index is necessary for the device FK to succeed
            UNIQUE INDEX `idk_ContactTuple` (CEO,CFO,CIO), -- No duplicates ever. Good for re-use
        
            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
        (   -- An Expensive Device, typically our Supercomputer that requires Financing.
            -- This device is so wildly expense we want to limit data changes
            --
            -- Note that the GRANTS (privileges) on this table are restricted.
            --
            id INT AUTO_INCREMENT PRIMARY KEY,
            something VARCHAR(100) NOT NULL,
            CEO INT NOT NULL,   -- Chief Executive Officer
            CFO INT NOT NULL,   -- Chief Financial Officer
            CIO INT NOT NULL,   -- Chief Geek
            FOREIGN KEY `fk_device_2_tuple` (`CEO` , `CFO` , `CIO`)
                REFERENCES `tupleHolder` (`CEO` , `CFO` , `CIO`)
            --
            -- Note that the GRANTS (privileges) on this table are restricted.
            --
        );
        
        DROP SCHEMA testRealLifeTuple;
        

        此架构的要点归结为UNIQUE KEY表格中的tupleHolderdevice中的FK,GRANT限制(授予未显示)以及事实因为如上所述,设备被屏蔽了元组中的tomfoolery编辑:

        • 奖励
        • 必须尊重FK,因此tupleHolder无法与
        • 混淆

        如果tupleHolder被混淆了(3 contacts ids),则会违反FK。

        换句话说, NO WAY 与基于设备中单个列的FK设备相同,称之为[device.badIdea INT],这将FK返回到tupleHolder。标识。

        另外,如前所述,这与仅存在contacts不同。相反,重要的是contacts的组成存在,它是一个元组。在我们的情况下,元组已经过审查,并且具有信誉等级,并且在购买设备之后,该元组中的ID不会被搞砸,除非有足够的GRANTS允许它。即便如此,FK也已到位。

        可能需要15分钟才能收入,但存在巨大的差异。

        我希望这会有所帮助。