【问题标题】:Database normalization: Using separate tables to store a single field数据库规范化:使用单独的表来存储单个字段
【发布时间】:2012-03-11 18:25:15
【问题描述】:

目前我们的数据库已设置好,以便支付交易记录支付类型 ID,并链接到包含这些值的支付类型(现金、支票、信用)表。示例:

支付交易:

  • 身份证
  • 金额
  • 日期
  • 付款类型 ID

付款方式:

  • 身份证
  • 付款方式(现金、信用卡)

我的问题是我是否应该删除支付类型表,并将支付类型值作为文本存储在支付交易中。

这类似于this question。除了支付类型,可以肯定的是,无需为每种支付类型添加新信息。 'Cash' 没有链接到任何东西,我不需要知道关于 Cash 本身的任何信息,它就是。

据我所知,用单个字段替换付款类型表的优缺点如下:

优点

  • 在需要查找付款类型时删除大部分不必要的联接。
  • 交易的付款类型将始终准确反映交易记录时的情况。即,如果我将付款类型表中的“现金”记录更改为“信用”(无论出于何种原因),所有链接到现金的付款交易现在都将链接到信用。

缺点

  • 将支付类型存储为文本字段会减慢按支付类型排序的速度,并使这种排序比现在更加混乱。
  • 交易的付款类型将始终准确反映交易记录时的情况。即,如果我有一个拼写错误并且付款类型存储为“Kash”,我可以轻松修复该拼写错误,并且链接到该付款类型的所有交易都将自动更新。

我倾向于删除支付类型表并将单个字段添加到支付交易表中,您建议的最佳做法是什么?

【问题讨论】:

    标签: mysql database normalization


    【解决方案1】:

    我不同意你的任何一个赞成论点。

    在付款类型需要时删除大部分不必要的连接 找到了。

    您只是假设这将成为性能瓶颈。当你有数据说你必须做时,你应该做非规范化。这不是那个时代之一。

    交易的付款类型将始终准确反映 那是交易记录的时间。即如果我改变 付款类型表中的“现金”记录到“信用”(无论 原因),所有链接到现金的支付交易现在都将被链接 信用。

    您不应允许他人以这种方式修改付款方式。更改付款类型应该是另一笔交易,有自己的时间戳。

    任何关系数据库都可以处理 JOIN 和规范化表。我担心你犯了过早的优化。

    我会花更少的时间担心这个,而花更多的时间思考你将如何处理历史。在将交易移出历史记录表之前,您将保留多长时间?您是否考虑过根据时间戳按月对数据库进行分区?那会更值得你努力。

    【讨论】:

    • 我真的在更具体地谈论它们为开发人员/我懒惰的自我提供的好处。我知道 JOIN 对性能的影响很小(如果有的话),但是如果可能的话,写出没有 JOIN 的查询会更好。更改支付类型也是如此,用户没有能力这样做,但我们不得不重新排列支付类型是相当普遍的。与其依赖不同的 ID,我认为它更适合依赖静态的“现金”或“信用”,因为文本值不会发生太大变化。
    • 我看不到任何好处。我不同意它更好。我会反对它,但这是你的架构。
    • 我想我会保持原来的样子。每当更改付款类型时,必须更改一半的应用程序确实很痛苦,但我更愿意跟上最佳实践。谢谢!
    • 就像我说的,我建议将付款类型更改为具有自己时间戳的单独交易。就像您说的那样,您希望保留原始付款当天和更改发生时的付款类型。除非您有触发器来记录它,否则您不会通过 UPDATE 获得它。
    【解决方案2】:

    如果删除 PaymentType 表,则将外键检查替换为表 CHECK 约束:

    PaymentType   CHAR(6) NOT NULL CHECK(PaymentType IN('Cash', 'Credit', 'Cheque')
    

    好的——你把'check'写成'check';只是英语和美国之间的另一个区别。

    现在,这使得找出可能的值变得更加困难;您必须分析系统目录才能找到答案。使用单独的表格,您可以检查单独的表格以找出允许的内容。假设您开始跟踪“借记”与“贷记”分开;您向表中添加一行,而不是表架构更改。假设您决定需要记录未来交易中允许使用的代码(因此“现金”不再是一种选择)。您可以在 Payment Type 表中添加一列以指示此代码不再有效;使用简单的 CHECK 约束来做到这一点要困难得多。

    因此,即使您目前在 Payment Type 表中的数据有限或没有额外数据,我还是会使用 Payment Type 表,而不是在 Payment Transaction 表中嵌入支付类型。

    不过,如果这是我的设计,我可能会使用 CHAR(1) 或 CHAR(2) 代码作为支付类型的标识符,而不是数字列。当然,所有三种类型都以“C”开头,所以也许你会用“A”代表 cAsh,“H”代表 cHeck,“R”代表 cRedit(也许“D”或“E”代表借方或借方)带有 CHAR(1) 代码;使用 CHAR(2),您将使用“CA”、“CH”、“CR”(也许还有“DE”)。可以将全名存储在付款类型表中以供报告使用。在这种情况下,好处并不大,但在足够多的记录(足够多的足够小记录)上每条记录节省 4 个字节,它可能成为您存储成本的一个因素。当然,索引开销也发挥了作用;如果必须对 Payment Transaction 表中的列进行索引,则较小的字段使用较少的索引空间。

    【讨论】:

      猜你喜欢
      • 2012-09-12
      • 2015-03-23
      • 2019-05-14
      • 1970-01-01
      • 1970-01-01
      • 2014-11-01
      • 2012-04-07
      • 2015-09-23
      • 2012-12-24
      相关资源
      最近更新 更多