数据库设计:使用非密钥作为FK?

时间:2011-04-01 07:01:52

标签: mysql data-modeling database-design

说我有下表:

TABLE: widget
 - widget_id (not null, unique, auto-increment)
 - model_name (PK)
 - model_year (PK)

model_namemodel_year组成了一个复合键。在另一个表中使用widget_id作为FK有什么问题吗?

4 个答案:

答案 0 :(得分:1)

键是可用于唯一标识表中每一行的任意数量的列。

在您显示的示例中,您的窗口小部件表有两个键:

  • model_name,model_year
  • WIDGET_ID

在标准SQL中,外键可以引用引用表上的任何声明的键(主键或唯一键)。我需要检查MySQL的合规性。


来自foreign keys上的MySQL参考手册:

  

InnoDB允许外键引用任何索引列或列组。但是,在引用的表中,必须有一个索引,其中引用的列被列为相同顺序的第一列。


作为替代方案,如果您希望使用引用表中的复合键,那么该表中有两列对应于model_name和model_year,然后将外键约束声明为:

ALTER TABLE OtherTable ADD CONSTRAINT
     FK_OtherTable_Widgets (model_name,model_year)
     references Widgets (model_name,model_Year).

Re InnoDB vs MyISAM,在ALTER TABLE

的文档中
  

InnoDB存储引擎支持FOREIGN KEY和REFERENCES子句,它实现了ADD [CONSTRAINT [symbol]] FOREIGN KEY(...)REFERENCES ...(...)。请参见第13.6.4.4节“外键约束”。对于其他存储引擎,将解析子句但忽略这些子句。 CHECK子句被解析但被所有存储引擎忽略。请参见第12.1.17节“CREATE TABLE语法”。接受但忽略语法子句的原因是为了兼容性,以便更容易从其他SQL服务器移植代码,以及运行创建带引用的表的应用程序。请参见第1.8.5节“MySQL与标准SQL的区别”。

答案 1 :(得分:0)

我没有特定于my-sql的经验,但通常使用数据库建模

理解主键和辅助键之间的区别非常重要。 即使很多db(我确实知道Oracle确实)允许指定一个唯一的(简单的或复合的)密钥作为FK目标,这也不被认为是最佳实践。改为使用PK。

对于辅助密钥的FK应仅用于与不受您控制的表格相关联。

在你的特定情况下,我肯定会FK到widget_id:这是因为widget_id应该是你的PK,并且复合体只是唯一的(当然不是null)。这会导致在mane情况下获得更好的性能,因为您只在查询中加入一列,并且通常被认为是最佳做法(google'代理键'以获取更多信息)

答案 2 :(得分:0)

如果没有可以使用的列,MySQL将在列上创建一个索引:

  

InnoDB需要外国索引   键和引用键,以便   外键检查可以快速而不是   需要进行表扫描。在里面   引用表,必须有一个   索引所在的外键列   被列为第一列   同样的顺序。创建了这样的索引   在引用表上自动   如果它不存在。 (这是在   与一些旧版本形成鲜明对比   必须创建哪些索引   明确地或创造外国的   关键约束会失败。)   index_name,如果给定,则用作   如前所述。

http://dev.mysql.com/doc/refman/5.1/en/innodb-foreign-key-constraints.html

答案 3 :(得分:0)

假设您有两张桌子。第一个表格如下:

TABLE: widget
 - model_name (PK)
 - model_year (PK)
 - widget_id (not null, unique, auto-increment)

如果你想创建另一个引用第一个表中唯一记录的表,它应该是这样的:

TABLE B: sprocket
 - part_number (PK)
 - blah
 - blah
 - model_name_widget (FK to widget)
 - model_year_widget (FK to widget)
 - blah 

使用复合主键,您必须在FK引用中包含所有键字段,以确保您唯一地指定记录。