什么时候应该使用外键?

时间:2013-09-21 08:57:11

标签: sql sqlite

我刚开始学习SQL(使用SQLite),我正在试图找出应该使用外键的时间。它向我解释的方式是,任何时候重复数据出现都应该使用外键,只需保存ID以节省空间。我正在制作的数据库中有几千条记录,列出了类别和县(每列可能有几十个独特的记录)。因此,我可以为具有县名和主键ID的县创建一个单独的表,并对类别执行相同的操作。我毫不怀疑它会使数据库缩小约5%。但这是唯一的好处吗?似乎它正在使其他一切变得更加复杂。添加不需要的县和类别的ID。在phpLiteAdmin中查看表时,它只显示一个数字而不是类别/县名,这使得可视化变得更加困难。在这种情况下使用外键和制作单独的表有什么好处?或者我应该不这样做并坚持在一个表中的所有数据(重复和所有)?此外,将县/类别表只有一列没有数字主键是否有意义,因为它们都是独一无二的?这至少会在phpLiteAdmin中显示全名。提前谢谢!

5 个答案:

答案 0 :(得分:3)

如果您使用外键。它也被称为参照完整性。

假设您有两个表,第一个表是account_user,第二个是account_user_detail。 所以account_user表将具有account_id的account_number的主键。和account_user_detail表将具有帐户持有人地址详细信息。 因此,如果您同时关联两个表,则account_number或account_id将相同。 所以在第二个表中使用主键的值我们定义外键。 外键标识第二表中account_number的值是第一个表中具有相同帐号的Xyz先生的引用。

因此,外键用于连接两个表,这两个表与两个表共用,并共享相同的唯一值。

答案 1 :(得分:0)

您可以查看this

  

SQL外键约束用于强制执行“存在”关系   表之间。

修改: -

存在外键约束是为了保证引用的行存在。

wiki也说: -

  

数据库设计的一个重要部分是确保这一点   现实世界实体之间的关系反映在   数据库通过引用,使用外键从一个表引用到   另一个。[9]数据库设计的另一个重要部分是数据库   规范化,其中表被拆分并且外键生成   它们有可能被重建。

同时检查此线程。

Why are foreign keys more used in theory than in practice?

答案 2 :(得分:0)

如果您的国家/地区名称是“美国”,则为24字节。如果使用foriegn密钥,则只需2-4个字节。这是一个巨大的差异。

当您搜索国家/地区名称时,它将非常快,因为您只需匹配一个数字而不是整个字符串。

此外,如果您在country_id字段上使用索引,则会更小。

我能理解你指出增加的复杂性。在你的情况下,你可以逃避不使用外键,但你不应该。你最终会需要它们,以便更好地准备和体验这个主题。

答案 3 :(得分:0)

  

但这是唯一的好处吗?

没有

外键在逻辑上类似于大多数编程语言中的指针或引用。想象一下,尝试通过复制数据来制作一些数据结构,而不能引用任何东西。没有外键的数据库同样存在问题。

如果没有参考内容的能力,您必须确保所有副本都保持最新状态。如果有一个错误导致一个副本被更新而另一个副本没有被更新,这将有效地损坏数据 - 您将不再知道哪个副本是正确的。

避免冗余主要不是空间,而是数据完整性。数据库规范化的整个目的(没有外键就无法完成)是避免冗余,从而保护数据的完整性。


在您的特定情况下......

  • 类别(或国家/地区)是否能够存在而不连接到主表中的任何行?
  • 是否存在类别应存在的任何数据,与此类别所连接的主表中的哪些行无关?
  • 是否应该独立完成任何操作(如重命名)?

如果任一答案为“是”,则应将类别放入单独的查找表中。此查找表是否应使用自然(名称)或代理(ID)密钥是一个不同的问题。列出了一些优点和缺点here

答案 4 :(得分:0)

外键约束用于限制列或列集中允许存在的值。例如,结婚:

CREATE TABLE person
        (person_id INTEGER NOT NULL PRIMARY KEY
        , name varchar NOT NULL
        );

CREATE TABLE marriage
        ( person1 INTEGER NOT NULL PRIMARY KEY
        , person2 INTEGER NOT NULL UNIQUE
        , comment varchar
        , CONSTRAINT marriage_1 FOREIGN KEY (person1) REFERENCES person(person_id)
        , CONSTRAINT marriage_2 FOREIGN KEY (person2) REFERENCES person(person_id)
        , CONSTRAINT order_in_court CHECK (person1 < person2)
        );

-- add some data ...
INSERT INTO person(person_id,name) values (1,'Bob'),(2,'Alice'),(3,'Charles');

INSERT INTO marriage(person1,person2, comment) VALUES(1,2, 'Crypto marriage!') ; -- Ok
INSERT INTO marriage(person1,person2, comment) VALUES(2,1, 'Not twice!' ) ; -- Should fail
INSERT INTO marriage(person1,person2, comment) VALUES(3,3, 'No you dont...' ) ; -- Should fail
INSERT INTO marriage(person1,person2, comment) VALUES(2,3, 'OMG she did it again.' ) ; -- Should fail (does not)
INSERT INTO marriage(person1,person2, comment) VALUES(3,4, 'Non existant persons are not allowed to marry !' ) ; -- Should fail

SELECT p1.name, p2.name, m.comment
FROM marriage m
JOIN person p1 ON m.person1 = p1.person_id
JOIN person p2 ON m.person2 = p2.person_id
        ;

以上DDL试图模拟婚姻(并且部分失败)要建模的约束是:

  • 只有现有人才能结婚
  • 婚姻只能存在于两个不同的人之间
  • 一个人只能结婚一次

输出:

INSERT 0 3
INSERT 0 1
ERROR:  new row for relation "marriage" violates check constraint "order_in_court"
ERROR:  new row for relation "marriage" violates check constraint "order_in_court"
INSERT 0 1
ERROR:  insert or update on table "marriage" violates foreign key constraint "marriage_2"
DETAIL:  Key (person2)=(4) is not present in table "person".
 name  |  name   |        comment        
-------+---------+-----------------------
 Bob   | Alice   | Crypto marriage!
 Alice | Charles | OMG she did it again.
(2 rows)