我想知道您是否有一个网站,其中包含需要不同字段的十几种不同类型的列表(商店,餐厅,俱乐部,酒店, Activity ),是否可以使用创建具有如下定义列的表的好处?
示例商店:
shop_id | name | X | Y | city | district | area | metro | station | address | phone | email | website | opening_hours
或更类似于此的抽象方法:
object_id | name
---------------
1 | Messy Joe's
2 | Bate's Motel
type_id | name
---------------
1 | hotel
2 | restaurant
object_id | type_id
---------------
1 | 2
2 | 1
field_id | name | field_type
---------------
1 | address | text
2 | opening_hours | date
3 | speciality | text
type_id | field_id
---------------
1 | 1
1 | 2
2 | 1
2 | 3
object_id | field_id | value
1 | 1 | 1st street....
1 | 3 | English Cuisine
当然,如果预定义了值,可能会更抽象(例如:专业可以有自己的列表)
如果我采用抽象方法,它可能会非常灵活,但是带有许多联接的查询将变得更加复杂。
但是我不知道这是否会影响性能,执行这些“更复杂”的查询。
我想知道这两种方法的优点和缺点。我可以自己想象,但是我没有经验来确认这一点。 在我们进行合理讨论之前,需要澄清和解决某些问题。
必备解决方案
标签
在需要精确度的行业中,重要的是我们使用精确的标签以避免混淆,这样我们就可以进行交流而不必使用冗长的描述和限定词。
。
您发布为FixedTables的内容是 Unnormalized 。足够公平,可以尝试使用“第三范式”形式,但实际上它是一个未归一化的平面文件(不是“去归一化的”)。确切地说,您发布为AbstractTables的是 Entity-Attribute-Value ,是几乎但不完全是第六范式,因此比3NF更规范化,当然,假设正确完成了。
未标准化的平面文件未“未标准化”。它充满了重复(没有做任何操作来删除重复的组和重复的列或解决依赖项)和Null,它在许多方面都是性能浪费,并防止了并发。 为了进行Denormlaise,必须先对其进行归一化,然后出于某些充分的理由而使归一化稍稍后退。由于首先没有对其进行归一化,因此无法对其进行归一化。它只是未归一化。 不能说是“为了性能”而被非规范化的,因为它是性能 pig ,它与性能完全相反。好吧,他们需要缺乏形式化设计的理由],“为了性能”就可以了。即使是最小的正式审查也暴露了错误的陈述(但是很少有人可以提供,因此它一直隐藏着,直到他们让局外人解决,您猜对了,这是巨大的性能问题)。 规范化的结构要比未规范化的结构好得多。标准化程度较高的结构(EAV / 6NF)比标准化程度较低的结构(3NF / 5NF)更好。 我同意OMG小马的主旨,但不同意其标签和定义而不是说“除非必须,否则不要“非正规化””,而是说“忠实地标准化,定期”和“如果存在性能问题,则表示您未正确标准化”。
。 Wiki
关于“正常形式”和“规范化”的条目完全是个 Jest 。具体来说,这些定义是不正确的。他们混淆了普通表格;他们对规范化过程一无所知;它们对很久以前就被揭穿的荒谬或可疑NF给予同等的重视。结果是,Wiki增加了一个本已困惑且鲜为人知的主题。因此,不要浪费您的时间。
。
但是,为了取得进展,在没有该引用构成障碍的情况下,我要说这句话。
3NF的定义是稳定的,并且未更改。 3NF和5NF之间存在很多NF混淆。事实是,这是过去15年中取得的进步。许多组织,学者和供应商都对其产品进行了限制,他们跳起来创建了一个新的“Normal Form”来验证他们的产品。所有服务于商业利益和学术上不健全。 3NF处于其原始未篡改状态,旨在并保证某些属性。 总和是,今天的5NF是15年前3NF的目标,您可以跳过商业 Jest 和介于两者之间的大约十二种“特殊”(商业和伪学术)NF,其中一些是在Wiki中识别的,甚至在混淆术语中也是如此。
。 由于您已经能够理解和实现帖子中的EAV,因此您可以毫无疑问地理解以下内容。当然,真正的关系模型是先决条件,强键等。第五范式是,因为我们跳过了第四种:
第三范式
(用简单的明确术语来说)是,每个表中的每个非键列都与表的主键具有1::1关系,并且没有其他非关键列 零数据重复(如果勤奋地进行规范化,则结果;仅靠智力或经验,或者不通过正式工作而将其作为目标而实现)否更新异常(当您在某处更新一列时,不必更新位于其他位置的同一列;该列存在于一个且仅一个位置)。
。 第六范式当然是第五范式,加上:
消除丢失的数据(列)。这是Null问题(也称为处理缺失值)的一个真正解决方案,结果是没有Nulls的数据库。 (可以使用标准和Null替代品在5NF下完成,但这不是最佳选择。)如何解释和显示缺失值是另一回事。
。 EAV vs第六范式
我写的所有数据库,除了一个,都是纯5NF。我已经使用(管理,修复,增强)了几个EAV数据库,并且已经实现了一个真正的6NF数据库。 EAV是6NF的宽松实现,通常由对标准化和NF不太了解但可以看到EAV的值(value)并需要EAV灵活性的人员完成。你是一个完美的例子。区别在于:因为它很松散,并且因为实现者没有忠实的引用(6NF),所以他们仅实现所需的东西,并全部用代码编写;最终导致模型不一致。
。
鉴于纯6NF实现确实具有纯学术引用点,因此通常更为严格和一致。通常,这显示在两个可见元素中:
6NF具有包含元数据的目录,并且所有内容都在元数据中定义,而不是代码中。 EAV没有一个,一切都在代码中(实现者跟踪对象和属性)。显然,目录使添加列,导航变得容易,并允许形成实用程序。 了解 6NF后,它可以真正解决Null问题。由于EAV实现者缺少6NF上下文,因此它们会不一致地处理代码中丢失的数据,或者更糟的是,允许数据库中的Null。 6NF实现者禁止使用Null,并一致而优雅地处理丢失的数据,而无需代码构造(对于Null处理;当然,您仍然必须为丢失的数据编写代码)。
。
例如。对于具有目录的6NF数据库,我有一组proc将[重新生成]执行所有SELECT所需的SQL,并且我为所有用户提供5NF View ,因此他们不需要了解或理解底层6NF结构。 。它们被从目录中删除。因此,更改是容易且自动化的。由于没有目录,EAV类型手动执行此操作。
现在,我们可以开始
讨论
当然。但是不要太“抽象”。保持一致性,并以与其他列表相同的EAV(或6NF)方式实现此类列表。
关系数据库中的联接是行人。问题不在于数据库,而是问题是在处理联接时,SQL非常麻烦,尤其是复合键。 EAV和6NF数据库具有更多的Joins,它们与行人一样多。当然,如果您必须手动编写每个SELECT的代码,那么麻烦就变得很麻烦。 可以通过(a)在EAV上使用6NF以及(b)实现目录来消除整个问题,您可以从中生成(c)所有基本SQL。也消除了整个错误类别。 常见的说法是,以某种方式加入联接需要付出一定的代价。完全错误。联接是在编译时实现的,没有任何实质性因素可以“消耗” CPU周期。问题是要联接的表的大小,而不是这些相同表之间的联接的成本。在正确的PK⇢FK关系上连接两个表,每个表具有数百万行,每个表具有适当的索引(在parent [FK]侧为唯一;在Child侧为唯一)。 ;如果Child索引不是唯一的,但是至少前导列是有效的,则它较慢;没有可用索引的地方,那当然很慢。它与加入成本无关。在返回许多行的地方,瓶颈将是网络和磁盘布局。不是加入处理。 因此,您可以随心所欲地获得“复杂”的东西,没有成本,SQL可以处理它。
从实现,易用性(开发人员和用户),维护的 Angular 来看, 5NF(对于尚未取得进展的人为3NF)是最简单,最好的。缺点是,每次添加列时,都必须更改数据库结构(表DDL)。在某些情况下很好,但是在大多数情况下不是这样,因为适当的变更控制非常繁琐。其次,您必须更改现有代码(处理新列的代码不计算在内,因为这势在必行):在实现好的标准的地方,这要最小化;如果没有它们,范围是不可预测的。 EAV(这是您发布的内容),允许在不更改DDL的情况下添加列。这就是人们选择它的唯一原因。 (处理新列的代码不计算在内,因为这是必须的)。如果实现得当,它将不会影响现有代码;如果没有,它将。但是,您需要具有EAV功能的开发人员。当EAV实现不当时,这是可恶的,这比5NF实现得不好更糟,但不会比大多数数据库都存在的Unnormalized更糟糕(错误地表示为“针对性能而标准化”)。当然,拥有一个强大的Transaction上下文(比5NF / 3NF更为重要),因为这些列的分布更为分散。同样,必须保持声明式引用完整性:我所看到的困惑很大程度上是由于开发人员删除了DRI,因为它变得“太难维护”了,结果是,正如您所想象的那样,数据的母亲堆满了重复的3NF / 5NF行和列。并且不一致的Null处理。 假定已针对预期目的合理配置了服务器,但性能没有差异。 (好吧,只有在6NF中才有可能实现特定的优化,而在其他NF中则无法实现,但是我认为这超出了本线程的范围。)同样,EAV表现不佳会导致不必要的瓶颈,仅此而已。未规范化。 当然,如果您使用EAV,我建议您提供更多的手续;买完整的交换;配6NF;实现目录;产生SQL的实用程序;意见;始终处理丢失的数据;完全消除Null。这减少了您对开发人员质量的脆弱性;他们可以忘记EAV / 6NF的深奥问题,使用 View ,并专注于应用程序逻辑。
请原谅。