使数据库ID一致且“可读”的优缺点

时间:2011-02-09 22:24:06

标签: database database-design data-driven

问题

数据库ID“无意义”是一个很好的经验法则吗?相反,以一种可以一目了然地识别ID的方式构建ID会有很大的好处吗?有什么优点和缺点?

背景

我刚和我的同事讨论过我们数据库中ID的一致性。我们有一个利用spring的数据驱动应用程序,因此我们很少需要更改代码。这意味着,如果出现问题,数据更改通常就是解决方案。

我的观点是,通过使ID一致且可读,我们可以节省大量时间和长期头痛。一旦设置了ID,它们就不必经常更改,如果做得对,未来的更改也不会很困难。我的同事的立场是ID永远不会重要。将信息编码到ID中会违反数据库设计策略并使其有序保持需要额外的工作,“我们没有时间。”我在网上找不到任何支持这两个职位的东西。所以我转向SA的所有大师!

示例

想象一下这个简化的数据库记录列表,表示食品杂货店中的食物,第一组代表具有编码在ID中的含义的数据,而第二组则不代表:


ID含义:

Type
1 Fruit
2 Veggie

Product
101 Apple
102 Banana
103 Orange
201 Lettuce
202 Onion
203 Carrot

Location
41 Aisle four top shelf
42 Aisle four bottom shelf
51 Aisle five top shelf
52 Aisle five bottom shelf

ProductLocation
10141 Apple on aisle four top shelf
10241 Banana on aisle four top shelf
//just by reading the ids, it's easy to recongnize that these are both Fruit on Aisle 4

ID无意义:

Type
1 Fruit
2 Veggie

Product
1 Apple
2 Banana
3 Orange
4 Lettuce
5 Onion
6 Carrot

Location
1 Aisle four top shelf
2 Aisle four bottom shelf
3 Aisle five top shelf
4 Aisle five bottom shelf

ProductLocation
1 Apple on aisle four top shelf
2 Banana on aisle four top shelf
//given the IDs, it's harder to see that these are both fruit on aisle 4

摘要

保持ID可读且一致的优缺点是什么?您通常喜欢哪种方法?为什么?是否有公认的行业最佳实践?

--------编辑( 来自评论的有用背景信息, ):--------

在我们的表中,主键始终是包含唯一整数的ID字段。起初,该整数是任意的。随着时间的推移,其中一些ID在开发人员/测试人员中自然具有意义。在最近的重构期间,某些开发人员也花时间使所有ID更容易识别。它使每个人的工作变得更容易100倍。由于理论上的原因,一些人(实际上并没有使用数据/代码)强烈反对。在实践中,没有一个反对意见是正确的。此外,所有使用这些数据的开发人员都认为它现在更容易维护。

我正在寻找(但尚未见到)反对在以数据为中心的环境中使用可立即识别的ID的辩护理由。

11 个答案:

答案 0 :(得分:20)

Con:我刚刚将“Aisle Five top shelf”更改为“Aisle Six top shelf”,所以现在我必须将其ID更改为61,现在我必须将“Grapes on Aisle five top shelf”的ProductLocation ID更改为是10461和哦上帝在我的数据库中的ID位置ID字符串显示在哪里哦上帝谁设计ID携带意义应该是在早上四点拍摄,一切都疯了,为什么“过道七底架” ID为41模具。

答案 1 :(得分:5)

使用数据库ID编码有关行的信息有几个问题。如果您希望您的胡萝卜的“ID”为203,则应添加product_id列(例如)并将此信息放在那里。为什么呢?

  1. 通过自定义ID,您必须添加管理ID的特定于域的代码,并且不能依赖自动递增或UUID等数据库功能。
  2. 如果您需要更改分类,则会破坏您的表格关系,浏览器书签,搜索引擎结果等。
  3. 这不常见 - 因此当您将特定于应用程序或域的数据放入ID字段时,许多人会认为这是无意义的信息,而不是。您将需要一个数据字典(并且您必须确保人们读取数据字典)以注意这是有价值的信息。
  4. ID唯一需要的目的是唯一标识表中的行。如果它可以提供良好的查找性能,这是一个奖励,如果它可以紧凑存储,那是另一个奖励。但它不应包含有关其标识的行中的实体的任何信息,除了该实体的唯一标识符。

答案 2 :(得分:4)

“可读”是什么意思? ID通常只是数字。你说“一致”是什么意思? ID通常只是递增数字;你不能比那更加一致。当信息已经明确地存在于数据库中时,为什么要浪费时间和精力来将信息编码到ID中?谁会使用“有序”的身份证?

答案 3 :(得分:4)

好吧,鉴于你的10141“Apple已经过道四”,当您在货架10的过道1中收到产品41时会发生什么?或者该产品1位于货架014上的过道1,或者是位于地板上的过道101中的产品41,因为它不在货架上?

一旦开始混合这样的数据,您通常会失去可靠地提取组件的能力。人类可读的键都很好用,但你永远不会破坏人类表单所基于的个人ID。

答案 4 :(得分:3)

有意义的ID不符合“数据库设计策略”!

恰恰相反,它正是真正的关系数据库从第一天开始的。如果您的数据包含某些属性组合 - 从业务角度来看 - 唯一,那么将其作为ID通常会破坏Boyce-Codd的正常形式。并带来与之相关的异常现象。

除非ID中编码的信息与其他字段中的信息一样多,否则只需使用它即可。如果它是冗余的,请创建一个多列主键。它们对ORM来说不是很方便,但在数据驱动的应用程序中它们是一种祝福。

ADDENDUM:(原始问题编辑后)

在您的情况下,对于数据驱动的应用程序,我会这样做:

Type
==========
Fruit
Veggie

Product
==========
Apple    Fruit
Banana   Fruit
Orange   Fruit
Lettuce  Veggie
Onion    Veggie
Carrot   Veggie

Isle
==========
4
5

Shelf
==========
top
bottom

Location
==========
4   top
4   bottom
5   top
5   bottom

ProductLocation
==========
Apple    4  top
Banana   4  top

使用这样的设置:

  • 数据已标准化
  • 您可以在ProductLocation表中查看任何产品的位置 - 您甚至可以看到货架
  • 没有代理人
  • 根据查询的类型,这种结构实际上可以比其他命题更好地执行,因为它需要更少的连接(或者它可能更慢,因为它需要更多的存储)。
  • 这对于支持“替换更新”约束的RDBMS最有效。
  • 如果你想把名字当作ids,你可能需要添加一些像“显示名称”这样的列。这是因为人们想要更改显示的内容而不是他们想要更改标记的身份。

答案 5 :(得分:3)

这是我对代理键的看法。 (或ID,如果你想打电话给他们)

代理键没有商业含义。它们用于唯一标识行。但他们做的不仅仅是识别行。他们也是排的“灵魂”。它无法更改或交易。如果代理遵循“灵魂”原则,那么当您删除行时,新行将永远不会获取死行的值。灵魂仍然属于被删除的行,即使它已经死了也不行了。

我喜欢我的代理人是“灵魂”,尽管这不是一个代理人。

代理人的优势在于它永远不需要改变。如果其他30个表具有主表的foriegn键,则当主表的PK更改时,您不希望更新所有30个表。你仍然可以在这个可能改变的值上有一个CANDIDATE键,但是因为它可以改变它不是行的灵魂。

代理键通常是自动递增整数。这为聚簇索引提供了完美的功能。你的表连接将尽可能好。自然键往往会产生可怕的聚簇索引,因为新值很少是连续的。整数是小的固定长度数据类型,可以更快地进行匹配。

如果你的名字改变了,你仍然是你。如果你烧掉你的指纹,你仍然是你。上帝正在使用代理键,所以我认为我们可以在我们的数据库中使用它们。

修改 的 在仔细阅读了你的问题后,我认为你实际上是以错误的方式使用“无意义的键”。

您有值“10141”来表示苹果/位置关联。这是2个代理人组合成1个领域。将它们保存为单独的字段“101”和“41”,并在这些字段的组合上进行PK。将它们分开将使搜索,索引,表连接等更容易。

你是对的,你不需要在映射表上另一个代理。 2个代理人的组合本身就是一个代理人(虽然不是灵魂)。只需在2个单独的列中表示组合,而不是组合成1列。 结束编辑

答案 6 :(得分:3)

关键设计的三个主要标准是熟悉,简洁和稳定。如果您使用熟悉且简单的密钥,则用户会发现它们更易于识别,记忆和使用。在输入和使用关键值和数据质量时,他们不太可能犯错,通常会提高可用性。

我建议你通过询问用户他们发现哪种类型的标识符更容易使用来解决这个问题,或者如果它对你非常重要,甚至可以用它们测试不同的方案。无论如何,开发人员不应该做出这个决定。一些组织的部门或个人负责定义要使用的标准编码方案。

答案 7 :(得分:2)

该ID可能对有意义,但不一定对计算机有意义。数据库软件不够智能,无法获得这样的模式(除非你编程这样做,显然,这将比它的价值更麻烦)所以你真正做的就是创造一个潜在的问题当与你没有预见到的身份证发生冲突时,为你自己做好准备。

我理解您正在尝试制作,但良好的数据库设计涉及使数据库引擎尽可能简单地进行写入和读取。您最好设置索引并研究数据库性能,以找到可以优化的区域。

答案 8 :(得分:1)

Zooko's Triangle以及petnames的概念可能与此相关。

答案 9 :(得分:1)

我考虑过将此作为评论,但我担心它可能过于复杂。

我认为一致意见认为,一般而言,ID不应具有意义。也许如果你更多地将你的问题限制在你的场景的细节上,那么意见会有所不同吗?

根据您的评论,这听起来就像您正在从电子表格中加载数据而我假设您使用有意义的ID作为确定不同数据之间关系的方式?

是否有理由不让数据库处理自动增量ID,而让用户(开发人员?)定义代码。这样,您可以通过外键维护参照完整性,并且还可以正确规范化。如果你真的需要快速查看一下 数据然后你可以有一个具有某种命名约定的计算列。它甚至可能对您的需求更有意义吗?

e.g。

Code Description
==== ===========
F    Fruit
V    Veggie

Product Code Product Type Product Description
============ ============ ===================
AP           F            Apple
BA           F            Banana

Location Code Location Description
============= ====================
AFTS          Aisle four top shelf
AFBS          Aisle four bottom shelf


Product Code Location 
============ ========
AP           AFTS 
BA           AFTS

实际上,位置可以进一步标准化为过道和货架,但你明白了。

当数据插入数据库时​​,会为每条记录创建ID,并且可以通过代码确定关系,并且可以将外键设置为正确的ID。然后,您的应用程序可以在不知道代码的情况下处理ID。

因此,产品位置看起来像:

Product ID Location ID
========== ===========
1          1 
2          1

如果您仍需要更具描述性的内容,您可以在SQL中加入以获取代码或创建计算列,或者您的应用可以将ID映射到缓存中的代码。

e.g。

Product ID Location ID ProductCode_LocationCode
========== =========== ========================
1          1           AP_AFTS
2          1           BA_AFTS

这会有点受到性能影响,但我仍然没有看到这一点,但也许这有助于你?

好的,那太久了。 :)

答案 10 :(得分:0)

我认为这没什么大不了的。当我有机会时,我总是倾向于重新设置我的身份,但那只是我。我想如果你在你的id中有一些顺序是有用的,如果你在代码[enum的例子]中引用它们,除此之外我不会担心它。