优点&日期列的缺点作为主键的一部分

时间:2018-04-26 12:31:03

标签: sql sql-server database primary-key composite-primary-key

我目前正在开发一个数据库,需要一个日志来跟踪一堆不同的数据变化。价格变化,项目状态变化等等。为了实现这一点,我制作了不同的“日志”表,用于存储需要保存的数据。

举一个可靠的例子,为了跟踪需要订购的零件的价格变化,我创建了一个名为Part_Price_Log的表。主键是由修改零件价格的日期和Parts表上零件唯一ID的外键组成的组合。

我的逻辑是,如果您需要查找零件的当前价格,您只需要找到该零件ID的最新条目。但是,我被告知不要以这种方式实现它,因为使用Date作为主键的一部分是一种简单的方法来获取数据中的错误。

所以我的问题就是这样。

使用Date列作为复合主键的一部分有哪些优缺点?有哪些更好的选择?

4 个答案:

答案 0 :(得分:3)

一般来说,我认为最好的主键是合成自动增量键。这些都有一定的优势:

  • 键值记录了广告订单。
  • 密钥是固定长度的(通常为4个字节)。
  • 对于外键引用,单个键更加简单。
  • 在基于主键对数据进行聚类的数据库(例如默认情况下为SQL Server)中,插入“最后”。
  • 它们相对容易打字和比较(我的眼睛不适合比较UUID)。

根据您的数据建议,其中第四个是包含大量插入的数据库中的一个非常大的问题。

复合主键没有先验错误。它们有时很有用。但这不是我想要的方向。

答案 1 :(得分:1)

在不了解您的域名的情况下,建议真的很难。您如何识别现实世界中的一部分?我们假设您使用EAN。这是你的“自然钥匙”。现在,每次价格变化时,一部分是否会获得新的EAN?可能不是,在这种情况下,零件价格的真实世界标识符是其EAN与该价格有效的时间段的组合。

我认为关于“一种简单的方法来获取数据错误”的评论指的是时间数据库不仅本质上更复杂(它们还有一个额外的维度 - 时间),对时间功能的支持是缺乏大多数SQL DBMS。

例如,您选择的SQL产品是否具有interval数据类型,或者您是否需要使用一对start_dateend_date列来推广自己的产品?您选择的SQL产品是否具有表内约束的能力,例如防止同一部分的重叠或非并发间隔?您的SQL产品是否具有轻松查询时态数据的时态函数?

答案 2 :(得分:1)

根据性能要求以及查询此表的频率,优缺点会有所不同。

作为第一个例子,请考虑以下事项:

GHCi> foo (\m -> m (show . not))
"False"
GHCi> bar (\m -> m (show . not))
"False"

如果CREATE TABLE Part_Price_Log ( ModifiedDate DATE, PartID INT, PRIMARY KEY (ModifiedDate, PartID)) 是第一个并且这是一个只有插入行的日志表,那么每个新行都将放在最后,这很好(减少了碎片)。如果您希望按ModifiedDateModifiedDate + ModifiedDate直接过滤,则此方法也很有用,因为PartID是主键中的第一列。这里的con将是ModifiedDate搜索,因为主键的聚集索引将无法直接搜索PartID

第二个例子是相同但反向的主键排序:

PartID

这适用于CREATE TABLE Part_Price_Log ( ModifiedDate DATE, PartID INT, PRIMARY KEY (PartID, ModifiedDate)) 的查询,但PartID直接查询的数据不多。首先使用ModifiedDate会使插入替换数据页,因为插入的PartID低于最大PartID(这会增加碎片)。

最后一个例子是使用代理主键,如PartID

IDENTITY

这将使所有插入最后一次并减少碎片,但您需要一个额外的索引来查询您的数据,例如:

CREATE TABLE Part_Price_Log (
    LogID BIGINT IDENTITY PRIMARY KEY,
    ModifiedDate DATE,
    PartID INT)

关于最后一个的问题是插入操作将花费更长时间(因为索引也必须更新),并且由于索引,表的大小将增加。

另请注意,如果您的数据允许同一天的同一部分进行多次更新,那么使用复合CREATE NONCLUSTERED INDEX NCI_Part_Price_Log_Date_PartID ON Part_Price_Log (ModifiedDate, PartID) CREATE NONCLUSTERED INDEX NCI_Part_Price_Log_PartID_Date ON Part_Price_Log (PartID, ModifiedDate) 会使第二次更新失败。您在此处的选择是使用代理键,使用PRIMARY KEY代替DATETIME(将为您提供更多的更新余量),或使用DATE而不使用CLUSTERED INDEXPRIMARY KEY约束。

我建议做以下事情。您只保留一个索引(实际表格,因为它是群集的),订单始终是插入的,您不必担心重复的UNIQUE具有相同的ModifiedDate,您的查询将按日期进行快。

PartID

答案 3 :(得分:0)

我同意在这种情况下最好将标识列/ uniqueidentifier保留为主键,如果将partid和date设置为复合主键,则在两个并发用户尝试更新的情况下,它将失败在这种情况下,主要密钥将失败。因此,更好的方法是将标识列作为主键并继续转储日志表中的更改。如果您稍后遇到一些性能障碍你可以明智地对你的桌子进行分区,并且可以克服性能挑战。