【问题标题】:Database Tables, more the better?数据库表,越多越好?
【发布时间】:2010-05-28 22:46:10
【问题描述】:

最近我一直在重新思考几个月前所做的数据库设计。主要原因是昨晚我阅读了 vBulletin 的数据库架构,发现他们使用了很多很多表。

我用于架构(例如我的日志表)的当前“想法”是通过用整数区分日志类型来将所有内容保存在一个表中:

id, type, type_id, action, message
1 ,    1,     305,      2, 'Explanation for user Ban'
2,     2,    1045,      1, 'Reason for deletion of Article'

其中type 1 = user, type 2 = articletype_id = the ID of the user, article or w/eaction 2 = ban, action 1 = deletion

要不要把设计改成两个表logBanslogSomething等等?还是保留我目前使用的方法更好?

【问题讨论】:

    标签: mysql database database-design data-modeling


    【解决方案1】:

    这里的问题是subtyping。处理子类型有三种基本方法。

    1. 将每种记录类型放入一个完全独立的表中;
    2. 在父表中放一条记录,然后在子类型表中放一条记录;和
    3. 将所有记录放在一个表中,为“可选”数据(即不适用于该类型的数据)提供可为空的列。

    每种策略都有其优点。

    例如,如果不同子类型之间几乎没有差异,则 (3) 特别适用。在您的情况下,如果不同的日志记录属于特定类型,它们是否有额外的列?如果他们不这样做,或者他们确实将它们全部放在一张桌子上的情况很少。

    (2) 通常用于 Party 表。这是 CRM 中的一个常见模型,它涉及具有 Person 和 Organization 子类型的父 Party 对象(Organization 也可能具有 Company、Association 等子类型)。 Person 和 Organization 具有不同的属性(例如 Person 的称呼、名字、出生日期等),因此将其拆分而不是使用可为空的列是有意义的。

    (2) 可能更节省空间(尽管现代 DBMS 中 NULL 列的开销非常低)。更大的问题是 (2) 可能会让开发人员更加困惑。你会遇到这样一种情况,有人需要在某处存储一个额外的字段,然后将它放在一个对该类型为空的列中,因为这样做比获得 DBA 批准添加一个列更容易(不,我不是在开玩笑)。

    (1) 在我的经验中可能是 3 中最不常用的方案。

    最后,必须考虑可扩展性,这可能是 (1) 的最佳情况。在某些时候,JOIN 不能有效地扩展,你需要使用某种分区方案来减少你的表大小。 (1) 是这样做的一种方法(但是一种粗略的方法)。

    不过,我不会太担心这一点。在成为问题之前,您通常需要获得数亿或数十亿条记录(除非您的记录真的非常大,在这种情况下它会更快发生)。

    【讨论】:

    • Cletus 一如既往的出色。阅读您的答案总是很高兴,因为您实际上开发了答案并就为什么以及如何给出了很好的解释。谢谢。
    • 只是关于 (2) 的注释,如果您有一个鉴别器(即提示实际“叶”类型的列),您可能会受益于 DBMS 支持的分区并提高查询性能针对特定的“叶子”类型。不过,仅当您存储了大量对象时才值得这样做。
    【解决方案2】:

    这取决于。如果您将拥有 1500000000 个类型 1 的条目和 1000 个类型 2 的条目,并且您将对类型 2 进行大量查询,请将这些表分开。如果没有,只保留一张桌子更方便。

    牢记可扩展性:

    • 1 年内每种类型我会有多少个条目?

    • 我将在此表上执行多少个请求?

    • 您能否在某个时候清除此日志?你能把它移到另一个表(比如超过 X 个月的存档条目)吗?

    【讨论】:

      【解决方案3】:

      我现在看到的一个缺点是您无法在 type_id 上强制执行外键完整性,因为它指向许多不同的表。

      【讨论】:

        【解决方案4】:

        我想添加一个小提示。有点离题,而且很基本,但是使用enum 而不是tinyint 来表示状态标志要清楚得多,即

           enum('user','type')
        

        如果只有两种状态,tinyint 的内存效率会更高一些,但不太清晰。 enum 的另一个缺点是您将部分业务逻辑放在数据层中 - 当您需要添加或删除状态时,您必须更改数据库。否则会更清楚,我更喜欢enum

        【讨论】:

          【解决方案5】:

          我会尽可能地具体化——在这种情况下,我会创建两个表。 每张桌子都有一个特定的用途,所以我看不出你为什么要把它们结合起来。

          【讨论】:

            【解决方案6】:

            我不会像 vBulletin 那样做。像 vBulletin 这样的旧应用程序的问题在于,虽然它们可能一开始是精益机器,但随着时间的推移,它们会收集大量熵并最终变得臃肿。由于有插件、第三方工具和开发过旧代码的开发人员,因此破解它是一个艰难的选择。

            这就是为什么这里没有进行太多重构的原因。不要让它们成为你的编程模型。环顾四周,找出最有效的方法并使用它。很多桌子对我来说听起来是一件坏事,不好。

            【讨论】:

            • 很多表通常比几个表更好的选择。这称为规范化。
            • 伙计,我知道规范化。你知道数据库膨胀吗? “随着时间的推移,他们收集了大量的熵并最终变得臃肿。因为……打破它是一个艰难的选择。”你很难理解
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2012-10-03
            • 2013-07-19
            • 1970-01-01
            • 2013-07-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多