Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/77.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 复合主键:是好还是坏_Sql_Database_Database Design_Relational Database - Fatal编程技术网

Sql 复合主键:是好还是坏

Sql 复合主键:是好还是坏,sql,database,database-design,relational-database,Sql,Database,Database Design,Relational Database,我一直在为一个网上商店系统设计一个数据库。通过阅读本网站的一些帖子,我遇到的问题是,尽管我可以在下面解释的情况下使用复合主键,但这真的是一种不好的做法吗(根据我在stackoveflow上读到的这方面的帖子,很多人说这是一种不好的做法,这就是我为什么要问的原因) 我想将订单付款存储在一个单独的表中。原因是,订单可以有多个项目,这些项目以多对多关系的形式在单独的表中处理。现在,如果我不为付款表使用复合主键,我将丢失唯一的PaymentID: [PaymentId] INT IDENTITY(1,1

我一直在为一个网上商店系统设计一个数据库。通过阅读本网站的一些帖子,我遇到的问题是,尽管我可以在下面解释的情况下使用复合主键,但这真的是一种不好的做法吗(根据我在stackoveflow上读到的这方面的帖子,很多人说这是一种不好的做法,这就是我为什么要问的原因)

我想将订单付款存储在一个单独的表中。原因是,订单可以有多个项目,这些项目以多对多关系的形式在单独的表中处理。现在,如果我不为付款表使用复合主键,我将丢失唯一的
PaymentID

[PaymentId] INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
[OrderId] INT NOT NULL PRIMARY KEY --Also a Foreign Key--
现在,如果我只是删除了
OrderId
的主键,我将失去这里的一对一关系,因此
多个OrderId可以关联到多个paymentid
,我不希望这样


这就是为什么先前在这里提出的问题得出结论(大部分)复合键是个坏主意。所以我想为自己澄清这一点;如果是坏的,那么最佳实践是什么?

没有结论认为复合主键是坏的

最佳做法是使用一些列或多个列唯一标识行。但在某些表中,单列本身不足以唯一标识行

SQL(和关系模型)允许复合主键。在某些情况下,这是一种很好的做法。或者,从另一个角度来看,在所有情况下,这都不是一个坏习惯

有些人认为,每个表都应该有一个自动生成唯一值的整数列,该列应该作为主键。有些人还声称,此主键列应始终称为
id
。但这些都是惯例,不一定是最佳做法。约定有一些好处,因为它简化了某些决策。但公约也有限制性

您可能有一个多付款的订单,因为有些人购买,或者他们有多个付款来源(例如,两张信用卡),或者两个不同的人想要支付订单的一部分(我经常和一个朋友去餐馆吃饭,我们每个人自己付饭钱,所以工作人员用我们的信用卡处理一半的订单)

我将按照以下方式设计您描述的系统:

Products  : product_id (PK)

Orders    : order_id (PK)

LineItems : product_id is (FK) to Products
            order_id is (FK) to Orders
            (product_id, order_id) is (PK)

Payments  : order_id (FK)
            payment_id - ordinal for each order_id
            (order_id, payment_id) is (PK)
这也与的概念有关。如果定义付款仅因为订单存在而存在,则将订单作为主键的一部分


请注意,LineItems表也缺少自己的自动递增单列主键。多对多表是一个很好地使用复合主键的典型示例。

这个问题非常接近征求意见,这可能会引发宗教战争。作为一个非常倾向于使用自动递增整数prim的人在我的表中(称为
TablenameId
,而不是
Id
),有一种情况是可选的

我想其他的答案可以解释为什么你需要主键

一个非常重要的原因是为了引用。在关系数据库中,理论上,任何实体都可以通过外键关系被另一个实体引用。对于外键,您肯定希望一列唯一地定义一行。否则,您必须处理不同表中与每个ot对齐的多个列她。这是可能的,但很麻烦


您所指的表不是“实体”表,而是“连接”表。它是一种用于处理多对多关系的关系数据库结构。因为它并不真正表示实体,所以不应该具有外键关系。因此,复合主键是合理的。在某些情况下,例如当您担心数据库大小时,会忽略人工主键关键甚至是可取的。

最佳实践在最好的情况下是有用的,但在最坏的情况下是盲目的。违背最佳实践不是罪过。只要确保你知道你在做什么样的权衡

数据库引擎可能是非常复杂的事情。如果不知道给定引擎进行了哪些特定优化,就很难确定哪种构造将产生最佳性能(因为我假设我们这里讨论的问题是性能).对于一种数据库中的大型表,复合键可能会有问题,但对于另一种数据库,复合键不会产生任何明显的影响


我学到的一个有用的实践是始终努力使我的应用程序尽可能简单。使用复合键是否可以避免插入前执行查找或其他一些麻烦?使用它们。但是,如果您注意到使用它们会使您的应用程序不再满足某些重要的性能要求,请考虑磁盘空间很便宜,因此在按约定命名的int标识(1,1)上聚集主键(如pk+表名)是一种很好的做法。它将使查询、联接、索引和其他约束易于管理

但是,有一个很好的理由不这样做(至少在MS SQL Server中是这样):如果您想在底层存储系统中管理数据的物理排序

主键决定物理排序顺序。如果在标识列上执行此操作,则物理排序顺序基本上就是插入顺序。但是,这可能不是最好的,尤其是当您总是以相同的方式查询表时。
在非常大的表上,获得正确的物理排序顺序会使查询速度大大加快。例如,您可能希望将聚集索引放在两个列的组合上。

如果我理解正确,在这种情况下,您只需在
OrderId
上添加一个单独的唯一约束,并将
PaymentId
作为主键