将语义数据存储在id中总是一个糟糕的主意吗?



这里有几个(不完整的)数据库表,它们存储有关酒店房间的信息。它们存储的信息是相同的,但是它们的设计是不同的:

  1. 单独列存储楼层信息:

    | id | floor 
    |----|-------
    | 1  | 1 
    | 2  | 1 
    | 3  | 2 
    | 4  | 2 
    
  2. 以id存储楼层信息

    | id 
    |-----
    | 101  
    | 102  
    | 201  
    | 202
    

像表2那样在id中存储语义数据是否总是一个糟糕的主意,或者是否有更有表现力的id足够有价值来证明它?

如果您想使用自然键,那么就使用自然键。不要将自然键命名为id

如果使用合成键,则将其视为必须唯一但没有其他含义的任意值。

这不是关于数据的语义,而是关于原子性和你是否违反了1NF。你应该问自己的问题是:

从数据管理的角度来看,房间号是否应该被视为一个原子数据 ?

换句话说,您是否总是从数据库中读取(并写入)整个房间号(无论您是否在客户端代码中将其视为一个整体)?

  • 如果是,您可以安全地将其设置为单个属性(然后将其设置为键或键的一部分,如果这是需要的)。是否也有代理键是另一回事(如下所述)。
  • 如果没有(例如:因为你需要查询楼层,或者使用楼层作为FK等),那么你必须将其拆分为单独的属性(例如楼层+每层房间),否则你将违反1NF。

注意:我不知道这是否是故意的,但是你的场景(1)没有包含足够的数据来重建房间号,所以它与场景(2)相比建模了一个不同的域。


顺便说一句,在键中存储语义数据本身并不是一个坏做法。如果某些属性或属性组合必须是唯一的,那么您必须为它们创建一个键,无论它们是否具有内在意义。您不能用"代理"键替换该键,您可以添加代理键(正如您可以想象的那样,它有其优点和缺点)。

我同意,这是个很糟糕的主意。id的思想是,它是行的单列唯一标识符,可以替代多列键。如果您将列称为"id",那么查看您的模式的任何人都希望看到主键。你也在失去语义价值,因为你知道那个东西是地板的表示。

如果您没有id列,并且只将列称为"floor",那么就可以了。你所关心的是,如果你需要找到一个特定的记录,你能做到吗?如果您的特定应用程序不需要查找floor以外的任何其他信息,那么继续使用"floor"作为列名,不要添加ID列。但是,如果您有一个复合键,如floor和hotel id,那么您可能希望再次添加id列作为"快捷"单列键,您可以将其用作其他表中的外键。

在表的主键中包含语义肯定是一个坏主意。

表中主键的作用是:

  • 是唯一的,
  • 作为记录的标识。

如果你把这样的语义放在主键中,那么你假设:

  • 所有房间都有楼层,
  • 不会有超过一家酒店,
  • 房间号不能有字母。

这些假设在未来很容易瓦解。然后,您需要更改现有记录的主键-这将使它们不再是记录的标识。

这样的逻辑也可以应用于其他情况。例如,您可以使用条形码作为图书的唯一标识符,但将来您可能会有没有条形码的图书。

话虽这么说,我甚至会进一步改变你原来的表,有id, room_numberfloor。有些酒店因为迷信,没有13011302等房间号。但这并不意味着他们没有第13层。

最后回答你的问题-这可能并不总是一个糟糕的想法,但我想不出一个例子,这不是一个坏主意。

是的,这总是一个糟糕的主意:

  • 如果后来"值"改变了,你也必须改变ID,这是一个更糟糕的主意
  • 如果您发现必须在两个具有数字相邻ID的现有行之间插入值数据,则没有空间容纳新ID
  • ID的目的是唯一地标识行。如果ID包含信息,你就重载了它的角色,这在编程中从来都不是一个好主意
  • 如果你将信息隐藏在ID中,你必须将再次提取出来,这会在使用的任何地方使用代码,这意味着工作量和维护
  • 你可能使用的任何框架将无法利用你的"优化";他们希望值在列中,而不是在ID
  • 的片段中。你到底在节省什么?磁盘便宜,软件/硬件现在是如此之快,节省是微不足道的,永远不会超过负面的

我过去也这么做过,但一直很后悔这么做,因为你无法预测未来,业务和数据也以你无法预测的方式变化。把自己锁在任何特定的世界观里都是危险的。事实上,我见过的每一个这样做的案例,都导致了很多问题。

KISS

用最高有效数字表示楼层的数字来识别房间绝对没有错。我想我住过的每一家酒店都是这样。我敢肯定,您的表格中必须有这样一个房间号属性。

对自己和别人的怀疑都是因为你把房间号叫做"id"。房间号是一个标识符——大概它是唯一真正重要的房间标识符——但如果这是你的属性所指的,那么就叫它"roomnumber",而不是"id"。

最新更新