我应该使用EAV模型吗?

30

我正在为一个电子商务应用程序设计数据库/域,但是我很难弄清楚如何存储产品。

这个网站将销售各种产品,例如笔、丁字裤、纹身、雨伞等等。这些产品会共享一些常见的属性,例如高度、宽度、长度、重量等等,但是有些产品有特殊的数据。例如,笔有不同的墨水颜色和笔尖/盖子,而小册子可以有不同类型的折叠方式。到目前为止,我已经想出了20多个额外的属性,但是这些属性可能只适用于网站上1%的产品。

因此,我想知道是否适合实现EAV模型来处理额外的数据。请记住,当客户在前端查看网站时,将会有类似于eBay和carsales.com.au的筛选侧栏。(因此要考虑到查询会比较频繁)

我不认为实现单表继承的方式是可行的,因为该系统需要保持灵活性。这是因为,将来我们可能会有更多的属性和新类型的产品。

我考虑的另一件事是使用NoSQL数据库(可能是MongoDB),但是我对这些类型的数据库了解甚少,那么它能解决我的问题吗?

选项评估:

  1. 拥有许多列的单个产品实体
  2. 分离的属性实体(EAV)
  3. 切换到无模式持久性

我正在构建一个带有属性实体的原型,以查看其灵活性,并测试性能和查询的控制程度。

编辑:当然,我也开放接受其他解决方案。


6
你为什么要手工制作电子商务应用程序?这可能会很困难、危险,也许有点不必要…… - Jonathan Day
刚刚发现了这个问题,看起来与你所问的几乎相同。 - BenV
1
@BenV,虽然问题相似,但答案可能会有很大的不同,特别是与Magento相关的部分。Magento最初确实在EAV性能方面遇到了困难,但他们通过仔细的缓存(查询、模型、HTML块和全页)和可选的去规范化来解决了这个问题。这些都是自那个问题被提出以来的新发展,值得在这种情况下重新提出这个问题,我个人认为。 - Jonathan Day
我正在开发的应用程序与典型的电子商务应用程序非常不同。我在 PHP 中找到的唯一可能的现有解决方案是 Magento,但它似乎相当复杂,并且学习它所需的时间和精力与从头开始制作自己的应用程序一样多。 - Cobby
8
@Cobby,说得对,您比任何人都更了解自己的要求,但恕我直言,如果您觉得学习Magento很复杂,那么编写自己的电子商务应用程序并不是我推荐的做法。像Magento这样的应用程序已经投入了成千上万的开发者和架构师小时数,并且在此过程中留下了许多伤痕。当您处理客户或客户的资金时,我宁愿看到别人过去犯过这些错误,而不是我... - Jonathan Day
3个回答

69
很好的问题,但当然,没有“唯一正确的方法”。根据@BenV的说法,Magento确实使用EAV模型。我的经验非常积极,但它确实会让其他用户感到困惑。需要考虑以下几点: 1. 性能。 EAV需要进行复杂的多表连接才能将相关属性填充到对象中。这会带来性能损失。但是,可以通过仔细的缓存(在整个堆栈的所有级别上,包括查询缓存)和有选择地使用去规范化来缓解这种影响。Magento允许管理员为分类和产品选择去规范化模型,其中SKU数量足以支持此操作(通常数千个)。这又需要触发重新索引的观察者(总是很好!),以及在产品数据更改时更新“平面”去规范化表。也可以安排计划或手动触发,并提示管理员。 2. 第三方用户复杂性 如果您计划将此应用程序提供给其他用户,则许多人会发现EAV过于复杂,最终你将不得不处理在用户论坛上大量的抱怨和无知的滥用(参考Magento!!)。 3. 未来可扩展性和插件架构。 毫无疑问,当可扩展性成为因素时,EAV模型真正发挥作用。非常容易将新属性添加到模型中,同时最大程度地减少破坏现有ORM和控制器代码的风险。 4. 数据类型的更改 EAV确实使更改属性数据类型稍微困难一些。如果您的初始设计需要某个属性数据类型,在将来更改(例如从intvarchar),则意味着您必须将该属性的所有记录迁移到与新数据类型匹配的相应表中。当然,纯粹主义者会建议您第一次就正确设计,但现实有时会干扰! 5. 手动产品导入 Magento默认支持基于CSV的产品导入,这可以让您在不使用脚本或插件的情况下快速高效地执行此操作。 但是,请注意,任何手动更新都可能影响性能和数据完整性。EAV模型让使用SQL和phpMyAdmin风格的CSV/XML几乎不可能导入产品(或其他实体)到数据库中。您需要编写一个导入器模块,接受结构化数据,并通过应用程序的模型层将其传递以将其持久化到数据库中。这会增加您的复杂性。

1
我认为性能不会是一个主要问题,Doctrine 2已经有了查询缓存,而且我将实现自己的级别。此外,重要的是要记住属性只有两个主要目的:1.过滤产品列表2.在产品页面上显示。属性中包含的数据仅是元数据,对于应用程序的工作并非必需。我想它们有点像标签,如果是这样,那么EAV似乎很实用。 - Cobby
2
@Cobby Jonathan提到了缓存的问题。您如何为过滤器生成总计?您如何高效地为大量客户提供页面服务?如果您坚持自己构建,请至少帮自己一个忙,审查Magento对其EAV系统所做的扩展以实现可扩展性。 - Joe Mastey
只是在替魔鬼辩护 - 我对EAV的感觉完全一样:http://weblogs.sqlteam.com/davidm/articles/12117.aspx#42216 我不是唯一一个有同样感觉的人:http://activecodeline.net/f-magento-eav - B00MER
2
EAV模型的一个优点是,通常可以在不更改数据库架构的情况下实现对架构的更改。这很重要,因为在MySQL中,ALTER TABLE语句会锁定表,在架构更改期间阻止所有读写操作。因此,如果您需要更改大型表上的架构,这可能会导致锁定问题和潜在的停机时间,而 ALTER TABLE 运行期间(想想非常大和关键的表,例如电子商务站点上的客户或产品)。 - Jim OHalloran
@JimOHalloran,在一个锁定是严重问题的生产环境中,一个主从设置是相当标准的,更改从节点后重新同步到主节点,然后交换主从角色并遵循同样的过程。如果两个数据库运行在不同结构上,则可能需要编写自己的工具来同步它们,但这将非常简单。 - Matt Dunbar

0
我建议你仔细研究一下带有OXM插件的Doctrine 2 ORM(https://github.com/doctrine/oxm)。它将解决你在不同属性方面遇到的问题。当然,你需要为可搜索的自定义属性构建索引,但我认为这不会是一个问题:)
如果你不在意社区成员的数量,那么你也可以使用MongoDB。

0
开源购物车Magento允许使用EAV设计为其产品添加自定义属性。您可以在这里查看它们的数据库架构。

1
是的,我已经审查了他们的数据库设计,这是我原型的基础。我的问题不是关于EAV的实现...我已经知道如何使用它。我的问题是关于在生产环境中使用EAV的架构实用性。 - Cobby

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接