MySQL表管理
MySQL表管理的问题是由于数据库记录中的重复导致的。为了解决这个问题,可以将重复的数据移动到单独的表中,并在其他地方引用它。这样,如果以后需要更改该数据,只需要在一个地方进行修改即可。
这对于正确的数据库设计至关重要,理论上应尽可能多地使用它来保持数据的完整性。然而,当从多个表中检索信息时,会损失一些性能,这就是为什么有时在性能关键的应用程序中可以看到使用非规范化的数据库表(也称为扁平化表)。
我的建议是在开始时进行良好的规范化,并且只有在真正需要的时候才进行非规范化。
此外,你可能会惊讶地发现,在事务性应用程序中,真正需要非规范化的数据非常少。在我设计的一个庞大应用程序中,有560个表的模式只有4个非规范化的数据项。
规范化还可以防止“更新异常”,通过消除某些重复来实现这一点。
“我的建议是在开始时进行良好的规范化,并且只有在真正需要的时候才进行非规范化。”这个建议是非常糟糕的!我仍然没有看到任何对这个“伪理论”的适当说明。-1。
请参考这篇文章:http://en.wikipedia.org/wiki/Database_normalization,了解更多关于数据库规范化以及所谓的“规范形式”的内容。
MySQL表管理问题的出现原因是数据的冗余和重复。当数据库中的相同信息在多个位置重复出现时,有可能在一个位置更新了信息但是在其他位置没有更新,导致数据损坏。
解决这个问题的方法是进行规范化设计,即设计一个数据库模式,避免重复和冗余的数据。规范化分为多个级别,从第一范式到第五范式。每个范式描述了如何消除特定的问题。
第一范式(1NF)特殊之处在于它不涉及冗余。1NF不允许嵌套表,具体来说就是不允许将表作为值的列。嵌套表在SQL中本身就不被支持,所以大多数关系型数据库默认都符合1NF。因此我们可以忽略1NF在后续讨论中。
第二范式到第五范式都涉及到在同一张表中多次表示相同信息的情况。
例如考虑一个关于卫星和行星的数据库:
Moon(PK) | Planet | Planet kind ------------------------------ Phobos | Mars | Rock Daimos | Mars | Rock Io | Jupiter | Gas Europa | Jupiter | Gas Ganymede | Jupiter | Gas
冗余很明显:木卫一是石头行星的卫星,木卫二也是石头行星的卫星。这不仅浪费了空间,更严重的是,这个模式可能导致不一致的信息:
Moon(PK) | Planet | Planet kind ------------------------------ Phobos | Mars | Rock Deimos | Mars | Rock Io | Jupiter | Gas Europa | Jupiter | Rock <-- 哦不! Ganymede | Jupiter | Gas
现在一个查询可能会返回不一致的结果,这可能会产生灾难性的后果。
规范化的设计将该表拆分为两个表:
Moon(PK) | Planet(FK) Planet(PK) | Planet kind --------------------- ------------------------ Phobos | Mars Mars | Rock Deimos | Mars Jupiter | Gas Io | Jupiter Europa | Jupiter Ganymede | Jupiter
现在没有事实被多次重复,因此不存在不一致数据的可能性。(可能看起来仍然存在一些重复,因为行星名称被重复使用,但是重复使用主键值作为外键不违反规范化,因为它不会引入不一致数据的风险。)
规范化的一个经验法则是,如果相同的信息可以用更少的单元格值来表示(不包括外键),那么应该通过将表拆分为更多的表来进行规范化。例如,第一个表有12个单独的值,而两个表只有9个单独(非外键)值。这意味着我们消除了3个冗余值。
规范化问题可以通过对概念模型进行一些思考来轻松避免,例如绘制一个实体-关系图。行星和卫星之间存在一对多的关系,这意味着它们应该用两个不同的表来表示,并通过外键关联起来。当多个具有一对多或多对多关系的实体在同一张表行中表示时,就会出现规范化问题。
规范化非常重要。如果数据库存在规范化错误,就会有可能将无效或损坏的数据输入到数据库中。由于数据“永远存在”,一旦损坏的数据进入数据库,非常难以清除。
不要害怕规范化。规范化级别的官方技术定义非常晦涩。它让人觉得规范化是一个复杂的数学过程。然而,规范化基本上只是常识,你会发现如果使用常识设计数据库模式,通常会完全符合规范化。
关于规范化还存在一些误解:
- 有人认为规范化的数据库速度较慢,而去规范化可以提高性能。但是这只在非常特殊的情况下才成立。通常来说,规范化的数据库也是最快的。
- 有时规范化被描述为一个渐进的设计过程,需要决定“何时停止”。但实际上,规范化级别只是描述了不同的具体问题。在第三范式以上解决的问题实际上是非常罕见的问题,所以很有可能你的模式已经符合第五范式。
规范化的原则在数据库之外不直接适用。但是规范化的基本思想-如果不同实例的相同信息可能不同步,就不应该有重复数据-可以广泛应用。这基本上是DRY原则的应用。
对于第一范式的例子,你给出的不完全正确。我总是通过“重复、冗余、非依赖”这些术语来记住第一到第三范式。重复数据是指当初级数据库开发人员编写的表定义中包含像DogName1、DogName2、DogName3等列时的情况。
为什么在面向对象编程中不需要规范化,而只有在数据库中才需要?我认为面向对象编程的核心已经内建了规范化过程,不是吗?
不,不是的。你总是可以将面向对象设计的状态简单地映射到一个“关系型”数据库/设计中的表中-这就是ORM的作用-但是你得到的数据库/设计是面向对象设计的关系表示,而不是面向对象设计的业务表示,而且这个关系表示很明显受到更新异常和冗余的影响,而规范化可以管理这些问题,而面向对象的方法必须通过手动实施适当的(未记录的)(复杂的)约束(“表示不变性”)来强制执行。
原则上规范化也适用于面向对象编程,只要不同对象中的相同信息(以可变形式)不重复出现,因为它们可能会不同步。
DogName1,DogName2,DogName3等可能是一个糟糕的设计,但它并不违反第一范式。
实际上它违反了第一范式。将多值属性转换为多个字段并不能减少对第一范式的违反。
是的,它违反了第一范式。第一范式意味着没有列允许集合或关系作为允许的值。多个带有单个值的字段不违反第一范式。
我们将不得不同意这个问题。由于SQL不支持多值字段,第一范式必须被解释为不要将多值属性转换为多个字段。
第一范式在E.F.Codd的论文《大型共享数据库的关系模型》中有明确定义。它的定义是关于域的,即列允许的数据类型。嵌套表是不被允许的,因为支持这一点会使查询语言变得复杂。这篇论文启发了SQL语言的设计。规范化的范式有着明确的定义,它不是一个可以“解释”为完全不同的含义的东西。