【问题标题】:Should I use a code in my lookup table我应该在查找表中使用代码吗
【发布时间】:2011-06-24 04:38:13
【问题描述】:

我正在使用 Orable 数据库,我正在添加几个查找表。

一般的问题是查找表应该包含代码和描述并且代码是返回到主表的 FK,还是查找表应该只包含描述并且是返回到主表的 FK。

我正在为代码/描述对争论。我觉得如果我有type = Contractorcode = CN 存储过程应该说where type='CN' 而不是只有type=Contractor 并且没有代码并且在存储过程中说这个:where type='Contractor' 因为如果我想显示:General Contractor 给用户,而不是Contractor。然后我将不得不更改存储过程。我觉得我不应该这样做。 (更改存储过程需要在开发中重新编译,迁移到测试,由客户端重新测试,以及迁移需要经过更改控制过程的产品,这需要两周的等待期;而修改表中的记录不需要任何这个)

我的数据建模者只想使用描述。他的主要论点是它需要一个不必要的连接。

应该怎么做?如果应该以代码/描述方式完成,我该如何说服数据建模者?

谢谢!

type_cd    type_dsc
CN         Contractor
IN         Inspector

【问题讨论】:

  • 你能发布一些示例数据吗?
  • 像什么?我在上面贴了一些东西。
  • 感谢大家提供非常好的答案,有这么多 godo 的。我试图选择我认为对阅读本文的其他人最有帮助的答案;这就是重点,对吧?感谢大家!哦,对我来说最终的解决方案是名称/描述对。类似于代码/描述选项,除了代码不是 2 个字符而是 30 个字符。这不是我的想法,而是我们新的“公司标准”。谢谢!

标签: sql database oracle database-design lookup-tables


【解决方案1】:

代码/描述。该代码值(我假设)将是一个更小、更有效的整数。此外,您不希望仅仅因为文本描述在未来某个时间发生变化而需要更新所有外键。

编辑:根据您刚刚添加的示例代码,我建议您将代码值设为整数值,而不是像“CN”、“IN”这样的字符串。您希望您的键值与与描述相关的任何“含义”无关。 “CN”仍然暗示“承包商”,如果/当该描述更改为“外部资源”时,“CN”将具有误导性。

【讨论】:

  • 你对整数提出了一个很好的观点,它在 sql 存储过程中意义不大。你怎么看他的论点?我编辑了我的问题。
  • @kralco626:我想我是在您发表评论的同时编辑我的答案。我认为“额外加入”的论点几乎没有水。通过对“代码”值进行适当的索引,连接根本不应该是一个问题。收益远大于成本。
  • @Joe - 我发现你关于整数整数的新论点。只要整数不是应该工作的自动生成。但是,代码中仍然没有任何意义。此外,长描述更容易改变,比如从承包商到总承包商,而不是逻辑想法,承包商到外部资源。但你提出了一个很好的观点。尽管我们所有其余的查找表都有 char(2) 键。
  • @kralco626:如果数据建模师不让步并假设数据建模师不是你的老板,我会说服你的老板你的方法是正确的,让他“鼓励”数据建模师去看看随心所欲。毕竟,这就是你的老板得到大笔报酬的原因! :-) 当然,您必须通过自己的特定企业文化来感受自己的方式。
  • @Joe - 是的,我要把这个标记为一个成功的前提。它是一个 varchar,所以它应该只占用必要的空间(当然这仍然比整数或 char(2) 中的空间更多)。另外,char(2)(2 bytes) 不是占整数(4 字节)的一半吗?那么 char(2) 键实际上不会比整数键更有效吗?
【解决方案2】:

使用数字 id 值和描述。 将 id 作为 FK 存储在主表中。

字符串是糟糕的 FK 值,基本规范化会告诉您的数据建模者,您希望灵活地在查找表中更改一次字符串,而不必在引用它的任何地方更改它。

【讨论】:

  • 您对整数提出了一个很好的观点,它在 sql 存储过程中意义不大。你怎么看他的论点?我编辑了我的问题。
  • 您应该能够在 SO 上找到大量关于使用整数作为 FK 以及驳斥关于连接​​成本的无效论点的参考资料。 - 主要归结为“这就是数据库所做的 - 他们擅长它。”只要在存储过程中有意义,您始终可以将 cmets 添加到您认为 id 引用的内容中,至少在您对数据进行定期系统维护时这些不会中断。
【解决方案3】:

嗯,这取决于这些代码的“标准”程度。

考虑一个像这样的查找表:

Code  Description
------------------
USD   United States Dollar
GBP   Pound Sterling
AUD   Australian Dollar
EUR   Euro

为此,我将使用char(3) 作为Code 并将其设为主键。您的代码似乎是 char(2) - 整洁、小巧;小于整数。

所以我的猜测是使用 Code 作为查找表中的 PK,而“主表”将 Code 作为查找表的 FK。

如果您的代码不是很标准并且可能会更改,则首选整数。

【讨论】:

  • 有趣。关于整数键比 CHAR(2) 更有效的论点,你怎么看
  • @kralco626, char(2) 是两个字节。查找表没有很多行。看不出在这种特殊情况下整数(4 字节)如何更有效。
  • @Damir - 好点。我无法想象比较整数比比较 char(2) 要好得多,如果有的话。加上一个索引...... likley 没关系。
  • 我仍然不会使用“代码”。而是将该缩写作为查找表中的另一个字段包含在内。那么您的 UI 可以使用它进行查询和显示,但您不会混淆数据存储。
  • +1 避免对所有内容都使用整数代码的狂热,尤其是在这些小型查找表上。在许多情况下,代码本身是不言自明的,您不需要加入。请记住,最快的 JOIN 是你甚至不做的。
【解决方案4】:

看,取决于键分布 - 对于大多数小型查找表,任何加入它的查询都将对查找和散列连接键进行全表扫描 - 所以数字与字符可能完全不是问题用于执行连接。

问题真的是 - 你需要加入吗?

我的意思是 - 如果您将查找存储为 UI 用作显示值,那么可以使用查找并加入它,以便您可以轻松更新显示值。

另一方面,如果您正在为多语言应用程序使用资源文件,并且您正在使用返回的代码作为查找,并且它是一小组预计不会更改的代码(Gender_Code = 'M' ale 或 'F'emale 或 'U'nknown 例如) - 然后使代码有意义,在字段上使用检查约束来控制值,甚至不用查找表,因为您通过代码知道它们UI 会弄清楚如何显示它们。

【讨论】:

    【解决方案5】:

    我的建议是使用 int ID 和 char/varchar 描述。

    在查询中使用 ID,仅在需要显示说明时链接到说明。

    不用担心 ID 与描述不同。这是它应该工作的方式。您需要一个不重要的 ID,这样没人会猜到“CH”或“EX”等的含义。将 cmets 添加到代码中,解释 ID 的含义。

    您希望能够在不破坏代码的情况下随时更改描述。您不想在所有代码更改时都修复它们。

    此外,您可以将一个或多个组添加到说明表中。如果您有多个承包商类型,您可以添加一个指示类型的组列。然后您可以链接到组描述表并返回组为 Contractor 的所有行。当然,这个组应该有一个带有 ID 和描述的查找表,以便您可以更改查找组的显示名称。

    告诉数据建模师您要将数据放入相关表中。这就是为什么它被称为关系数据库。

    【讨论】:

      【解决方案6】:

      很多事情都有现有的标准和编码方案,那些比我聪明的人有更多的时间去思考。例如,ISO 标准涵盖性别代码 (iso 5218)、国家代码 (iso 3166)、语言代码 (iso 639)、货币代码 (iso 4217) 等等。我去年买了Joe Celko's Data, Measurements and Standards in SQL,我真的很惊讶有多少官方维护的现成标准和编码方案。

      好的,所以偶尔有些国家会放弃他们的香蕉,转而支持欧元/美元,而现在您必须重写整个应用程序?不,您必须花几个小时编写脚本来合并/拆分任何更改的代码。大不了。为什么不在同一个版本中修复一些错误呢?

      就我个人而言,我几乎对所有必须编写代码的东西都使用短字符代码,或者当我需要根据某些“类型代码”分配行为时。代码与类型代码密切相关,那么为什么要让它变得更难呢?生成的代码更容易阅读,并且执行得更快,因为我需要更少的连接。对于其他所有内容(基本上都是用户生成的),我使用整数代理。

      我“只”使用数据库工作了 11 年,但我还没有看到很多“名称更改”如此显着以至于代码变得误导的案例。 “承包商”的类型代码,不能更改为“人力资源经理”或“副总裁”。那是一个新的代码。它可能会拆分为“内部/外部资源”,但这也需要更改代码,在这种情况下,我认为在项目预算中增加几个小时的数据转换不会有问题吗?

      最后,在某些时候,您必须承诺您在代码中输入的值。你可以使用任何你想要的值,但是它仍然意味着同样的事情

      我看过以下所有内容:

      where type = 1 /* contractor */ 
        vs
      
      int type_code = configfile.lookup("sqlcodes.contractor");
      ...
      where type = :type_code
        vs
      
       from sometable
       join contract_types using(type_id)
      where contract_types.type_name = 'Contractor';
      

      ...但我仍然没有看到这样做的好处:

      where type = 'CN'
      

      我想说的是:当我们花费 80 小时进行开发时,4 小时的数据库活动怎么会不符合项目预算呢?

      【讨论】:

      • 我确实看到了“在项目预算中增加几个小时的数据转换”的问题,因为它不仅仅是那些几个小时的编程。这也可能意味着更新十亿行表,这可以有效地使应用程序脱机。而且很容易避免,所以我不会走这条路。
      • 100% 正常运行时间是有代价的。许多典型的“质量属性”,如高可用性、安全性、性能、灵活性、可扩展性等,通常是相互排斥的。一个典型的数据库中有多少表有数十亿行?我认为这将是一种特殊情况。我什至认为不承认它是失败的。为什么要一个特殊情况来决定数据库剩余 99% 的设计?
      【解决方案7】:

      使用永远不会更改的助记符(例如,承包商的 CN 等)。让 UI 显示描述。一个小的代码表可能会放在一两个块中,因此通常会在缓存中找到,因此查找成本很低​​。

      最重要的是,未来的开发人员和后来必须将这些数据映射到其他系统的人(比如我)会感谢你,因为这意味着 80% 的时间你可以只查询表并直观地理解它。

      当我看到这样的桌子时,我只想尖叫:

      ADDRESS_ID
      HOUSE_NUMBER
      STREET_NAME
      STREET_TYPE_ID
      LOCALITY_ID
      
      SELECT * FROM addresses WHERE street_type_id = 10053;
      

      代码永远不必更改(它们在系统内部,最终用户不应该看到它们)。描述有时会发生变化,但通常不会变化很大。根据我的经验,描述变化如此之大以至于助记符不再有意义的情况非常罕见。

      【讨论】:

        【解决方案8】:

        总结所有答案,我认为查找表有四种选择:

        备选方案 1:
        • 说明(主键,较长的 varchar2 列)

        备选方案 2:
        • 代码(主键,一个短的 varchar2 列)
        • 说明(非空,更长的 varchar2 列)

        备选方案 3:
        • Id(无意义的主键,从序列派生的整数值)
        • 说明(非空,更长的 varchar2 列)

        备选方案 4:
        • Id(无意义的主键,从序列派生的整数值)
        • 代码(唯一键,短 varchar2 列)
        • 说明(非空,更长的 varchar2 列)

        主键列将位于主表中,顶部有外键约束。

        每个备选方案的一些特征:

        备选方案 1:
        • 查询主表时无需连接
        • 对主表进行即席查询时的明确含义
        • 主表需要更多存储空间
        • 主表上的索引将比其他替代品中的大得多
        • 更新描述值意味着维护问题和可能的应用程序停机时间。

        备选方案 2:
        • 要检索描述值时需要加入
        • 如果您想过滤某些查找值,则不需要加入:您可以为此使用代码值。
        • 对主表进行即席查询时的含义非常明确
        • 对主表的额外存储要求最低
        • 主表上的索引会很小。
        • 更新描述值很容易,但是代码通常是描述的缩写。更新描述值时,代码可能会变得混乱。

        备选方案 3:
        • 要检索描述值时需要加入
        • 过滤某些查找值时,您必须在查询中使用描述值,因为 ID 没有意义。
        • 对主表进行即席查询时含义不明确
        • 对主表的额外存储要求最低
        • 主表上的索引会很小。
        • 更新描述值很容易,不会像代码值那样引起混淆

        备选方案 4:
        • 要检索描述值时需要加入
        • 过滤某些查找值时需要加入,您可以使用查找表中的代码值。
        • 对主表进行即席查询时含义不明确
        • 对主表的额外存储要求最低
        • 主表上的索引会很小
        • 更新描述值很容易,您也可以非常轻松地更新代码值,使其与描述值相似。不过,在执行此操作时,您可能需要重新访问一些代码。

        个人意见:

        我会看看我打算如何使用主表和查找表。哪些查询很重要并且必须高效运行?价值观会改变吗?

        我个人的选择是备选方案 2 或 4。如果我绝对确定代码值永远不会改变,我会使用备选方案 2。这是罕见的。国家代码改变,社会安全号码改变。货币代码更改等。所以,大多数时候,我会选择备选方案 4。我不会那么担心额外的连接,尤其是因为查找表是一个小表。

        但是:选择适合您要求的替代方案。

        当您了解替代品的更多特征时,请随时编辑文本。

        问候,
        抢。

        【讨论】:

        • +1 非常棒的文章。您不仅提供了替代选项,还提供了每个选项最重要的特征/后果。我希望这个答案被接受。
        • 也许我弄错了,但是在备选方案 3 中,更新描述可能很容易并且不会破坏参照完整性,但它会破坏/使您的过滤查询所有无效,因为它们依赖于描述值而不是 ID(类似于更新备选方案 4 上的代码)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-27
        • 2021-11-12
        • 1970-01-01
        • 1970-01-01
        • 2015-08-31
        相关资源
        最近更新 更多