实体属性值数据库与严格关系模型电子商务的比较

142
可以毫不夸张地说,EAV/CR 数据库模型是糟糕的。然而,
问题是:应该使用什么数据库模型、技术或模式来处理描述电子商务产品的属性“类”,这些属性可以在运行时更改?
在一个好的电子商务数据库中,你会存储选项的类别(比如电视分辨率,然后为每个电视设置一个分辨率,但下一个产品可能不是电视,也没有“电视分辨率”)。如何存储它们,高效搜索,并允许用户设置具有描述其产品的可变字段的产品类型?如果搜索引擎发现客户通常根据控制台深度搜索电视,您可以将控制台深度添加到您的字段中,然后在运行时为每个电视产品类型添加一个深度。
好的电子商务应用程序之间有一个很好的共同特点,它们显示一组产品,然后有“钻取”侧面菜单,在那里你可以看到“电视分辨率”作为标题,并找到最常见的五种电视分辨率。你点击其中一个,它只会显示该分辨率的电视,让你可以通过选择侧面菜单上的其他类别进一步进行钻取。这些选项将是运行时添加的动态产品属性。
进一步讨论:
所以长话短说,有没有互联网上的链接或模型描述可以“学术地”修复以下设置?感谢Noel Kennedy建议一个类别表,但需求可能更大。我在下面用不同的方式描述它,试图突出其重要性。我可能需要一种视角校正来解决问题,或者我可能需要深入EAV/CR中。

喜欢EAV/CR模型的积极反应。我的同事们都说Jeffrey Kemp在下面提到的话:“新实体必须由专业人士进行建模和设计”(摘自上下文,请阅读他下面的回复)。问题是:

  • 每周添加和删除属性的实体
    (搜索关键字决定未来的属性)
  • 每周有新的实体到达
    (产品由零件组装而成)
  • 旧的实体每周消失
    (归档、不太受欢迎、季节性)

客户想要为产品添加属性,原因有两个:

  • 部门/关键字搜索/类似产品之间的比较图表
  • 消费品配置结帐前

这些属性必须具有重要意义,而不仅仅是关键字搜索。如果他们想比较所有有“鲜奶油糖霜”的蛋糕,他们可以点击蛋糕,点击生日主题,点击鲜奶油糖霜,然后检查所有有趣的蛋糕,知道它们都有鲜奶油糖霜。这不是特定于蛋糕,只是一个例子。


为什么不能只有一个具有对自身引用的外键的“类别”表? - Noel Kennedy
34
说“EAV数据库模型不好”既不安全也不准确,因为它很适合某些应用。 - spencer7593
如果您使用类似于Entity Framework 4的父类继承来装饰具有不同属性的各种对象,那么它是如何持久化这些对象的呢? - Zachary Scott
1
回到这篇关于一位顾问在基于极端版本的EAV系统上的经验的优秀文章。阅读它!https://www.simple-talk.com/opinion/opinion-pieces/bad-carma/ - Jeffrey Kemp
1
EAV是一个非常可行的数据库模型。我正在处理类似于你的问题,解决方案就是EAV。我建议阅读以下文章:http://sqlblog.com/blogs/aaron_bertrand/archive/2009/11/19/what-is-so-bad-about-eav-anyway.aspx - user1967599
有人能详细说明搜索查询性能吗? - Adelin
10个回答

78

以下是几个我能想到的优缺点,有些情况下一种方案比另一种更好:

选项1,EAV模型:

  • 优点:设计和开发简单应用程序所需时间较少
  • 优点:易于添加新实体(甚至可以由用户添加?)
  • 优点:具有“通用”界面组件
  • 缺点:验证简单数据类型需要复杂的代码
  • 缺点:对于简单报表来说,SQL 更加复杂
  • 缺点:复杂的报表可能几乎无法实现
  • 缺点:大型数据集性能较差

选项2,分别建模每个实体:

  • 缺点:需要更多时间收集要求和设计
  • 缺点:新实体必须由专业人员进行建模和设计
  • 缺点:每个实体需要自定义界面组件
  • 优点:实现数据类型约束和验证简单
  • 优点: SQL 易于编写、易于理解和调试
  • 优点:即使是最复杂的报表也相对简单
  • 优点:大型数据集的表现最佳

选项3,组合(“适当”地模型化实体,但为某些/全部实体添加“扩展”以获取自定义属性)

  • 优缺点:需要比选项1更多的时间来收集要求和设计,但可能不像选项2那么多 *
  • 缺点:新实体必须由专业人员进行建模和设计
  • 优点:稍后可能轻松添加新属性
  • 缺点:验证简单数据类型的代码很复杂(对于自定义属性)
  • 缺点:仍需自定义界面组件,但对于自定义属性可能会有通用接口组件
  • 缺点:只要包含任何自定义属性,SQL 就变得复杂
  • 缺点:一般表现良好,除非您开始需要按自定义属性搜索或报告

* 我不确定选项3是否会在设计阶段节省时间。

个人而言,我更倾向于选项2,并尽可能避免使用EAV。然而,在某些情况下,用户需要EAV提供的灵活性;但这也伴随着极大的代价。


如果您有一个单表,其中包含文本值1-n的索引,然后在C#中(在内存中)将您想要的内容映射到所需内容,会怎样呢?它仍将像EAV一样工作,但“匹配”将是领域模型。这有点像序列化,但您可以在索引的文本字段上使用SQL选择。不需要每个记录多次选择。所有“成本”都发生在RAM中。 - Zachary Scott
1
@Zim,这听起来很像选项3。每行有1-n个额外的“通用”列,并且存储在其中的数据在应用程序级别上进行解释。您可以获得将一个记录的所有数据放在一个地方的性能优势。但是,这些列的元数据需要存储在某个地方,这就是成本增加的地方。当然,我们可以将元数据缓存在RAM中,但它仍然比直接在应用程序代码中对域进行建模要花费更多。肯定比完整的EAV模型好! - Jeffrey Kemp
2
非常好的回答。现在人们在数据库设计和需求收集方面都有所节省。他们宁愿写一百倍于设计时间的代码行数,也不愿花时间做好设计。 - Tulains Córdova
如果你只提供选项1的结构,则在关系选项(2)中,你不需要比EAV选项(1)更多的设计。而且,关系接口是通用的,根据描述该结构的元数据来生成。这消除了所有选项2的缺点。但是,你忘记了唯一的实际缺点:DDL可能太慢以管理表格。 - philipxy
嗨@philipxy,我没有说“更多设计”。 EAV的存在是因为(假定)系统设计师可以花费更少的时间来设计模型,将这项设计工作留给以后的“用户”(这种缺乏专业设计导致了选项1列出的缺点)。如果EAV不会为设计师节省时间,那么只会增加拒绝EAV的理由。此外,我不同意DDL“太慢”的说法-因为它只需要很少的时间(即修复模型中的错误或实现新功能),所以其性能应该相对不重要。 - Jeffrey Kemp
嗨。我的设计观点是,存在理由是一个神话:当没有前期设计时,就没有SQL,而当设计发生时,EAV是复杂的且没有DBMS支持,而SQL是DDL+DML。我的DDL观点是,使用EAV的实际唯一原因是DDL太慢了。DDL精确地操作DBMS元数据表,就像DML操作EAV表一样,除非您希望在EAV情况下表示元数据的表上获得任何DBMS功能,而不仅仅是在重建后查询它,否则您正在自己开发DBMS。 - philipxy

65
可以说EAV/CR数据库模型不太好用,但实际上只是在关系数据库中使用效率低下。纯键值存储器与该模型结合使用效果很好。
现在来回答你的真正问题:如何存储各种属性并使其可搜索?
只需使用EAV。在您的情况下,它将是一个额外的单独表格。对属性名称和值进行索引,并且大多数关系型数据库管理系统会使用前缀压缩来处理属性名称的重复,使其变得非常快速且紧凑。
当您使用EAV / CR替换“真正”的字段时,这个模型变得很丑陋。与每个工具一样,过度使用它是“不好的”,并给它带来了不好的印象。

所以问题是,我有一个类别有15个额外字段,在EAV模型中需要16个表连接(包括主表),因此在产品搜索中需要进行16次左链接,并且如果客户需要,则有16个where条件,在300-400万条记录(一个人们出售二手产品的网站)中进行。这样会降低性能吗? - babak faghihian
2
如果这些“附加字段”已经定义好了,那么最好将其作为“真实字段”来处理。当然,在大型查询中执行无限数量的连接会产生很大的负担(但仍可能可行!)。在一个元数据密集的项目中,我允许每个“主要项目”有任意数量的“标签”(作为EAV记录),但是“大型查询”只选择一些预定义的标签名称,以限制连接的总数(目前典型的只有4个标签和约5个其他连接),当用户选择特定项目时,_然后_它会获取所有相关内容,但仅针对单个项目。 - Javier
但是,当然,那个特定的系统目前正在转移到hstore字段(这也是我们使用PostgreSQL的原因之一)。 - Javier

16
// 现在,我想花点时间向大家讲解Magento/Adobe PSD格式。 // Magento/PSD不是一个好的电子商务平台/格式。甚至不能说Magento/PSD是一个差的电子商务平台/格式。这样称呼对其他糟糕的电子商务平台/格式,如Zencart或OsCommerce都是侮辱。不,Magento/PSD是一个极其糟糕的电子商务平台/格式。我已经为此代码工作了数周,我的憎恨之情已经长成了难以扑灭的熊熊烈火,燃烧着千万个太阳般的激情。

http://code.google.com/p/xee/source/browse/trunk/XeePhotoshopLoader.m?spec=svn28&r=11#107

内部模型最多也就是古怪的,就像某人把模式放进了一个乱序的游戏中,然后将其封存并放到了油漆混合设备里……

现实世界:我正在开发一个中间件履行应用程序,这是其中一个查询地址信息的问题。

CREATE OR REPLACE VIEW sales_flat_addresses AS
SELECT sales_order_entity.parent_id AS order_id, 
       sales_order_entity.entity_id, 
       CONCAT(CONCAT(UCASE(MID(sales_order_entity_varchar.value,1,1)),MID(sales_order_entity_varchar.value,2)), "Address") as type, 
       GROUP_CONCAT( 
         CONCAT( eav_attribute.attribute_code," ::::: ", sales_order_entity_varchar.value )
         ORDER BY sales_order_entity_varchar.value DESC
         SEPARATOR '!!!!!' 
       ) as data
  FROM sales_order_entity
       INNER JOIN sales_order_entity_varchar ON sales_order_entity_varchar.entity_id = sales_order_entity.entity_id
       INNER JOIN eav_attribute ON eav_attribute.attribute_id = sales_order_entity_varchar.attribute_id
   AND sales_order_entity.entity_type_id =12
 GROUP BY sales_order_entity.entity_id
 ORDER BY eav_attribute.attribute_code = 'address_type'

懒惰地提供订单的精确地址信息

--

摘要:只有在以下情况下才使用Magento:

  1. 你会获得大量金钱
  2. 你必须使用
  3. 你享受痛苦

1
这是一篇较旧的帖子,但我真希望在3个月前开始为客户进行Magento项目时能够找到它。对于Boggle/颜料摇匀比喻点赞! - trevorc
1
相当有趣,Magento似乎是电子商务系统中的霸主。也许只是它的营销非常出色。 - Herr
1
Magento并不因维护水平而受欢迎,而是因为其可定制性,使任何人都能在不进行架构更改或少量修改的情况下实现新功能。但这种特性也是有代价的。 - Diego Mendes
1
如果想要避免前端和后端的三倍痛苦以及更多的痛苦,建议远离Magento 2。 - TheBlackBenzKid

15

我很惊讶没有人提到 NoSQL 数据库。

虽然我从未在生产环境下使用过 NoSQL(只测试过 MongoDB 并感到印象深刻),但 NoSQL 的整个重点在于能够将具有不同属性的项目保存在同一个“文档”中。


1
考虑到对MongoDB的写操作需要进行数据库级别的锁定,以及这对于并发生产流量意味着什么。 - Bill Karwin
考虑锁定持续时间在微秒级别。 - Hello World

13

对于一些不需要高性能的应用比如ETL,EAV有一个明显的优势: 差异化存储。

我实现了很多应用都有一个共同需求:能够查看一个领域对象从最初版本到当前状态的历史记录。如果该领域对象具有大量属性,则每次更改都需要插入新行到相应的表中(不是更新,因为这样历史记录会丢失,而是插入)。假设该领域对象是一个人,我要跟踪500,000个人,平均每个人在其生命周期内有100多次对各种属性的更改。再加上少有的应用只有1个主要领域对象,你很快就会发现数据库的大小会迅速失控。

一个简单的解决方案是仅保存主要领域对象的差异性变化,而不是反复保存冗余信息。

所有模型都会随着业务需求的变化而不断调整。使用EAV只是我们工具箱中的一种工具;但它不应被自动归类为“不好”。


2
“使用EAV只是我们工具箱中的一种工具,但它不应被自动归类为“不好”的。” - Catchops
顺便提一下,这被称为SCD(慢变化维度)。此外,双时间要求(Type 4 SCD的特定案例)需要使用EAV模式来处理具有此属性的属性。请记住,99%的NoSQL没有本地连接功能,因此如果您需要使用此类型的数据进行“实时”连接,则只能使用EAV。 - cowbert

3

我正在为同样的问题苦苦挣扎。你可以查看以下关于两个现有电子商务解决方案的讨论,这可能会对你有所帮助:Magento(EAV)和Joomla(常规关系结构):https://forum.virtuemart.net/index.php?topic=58686.0

看起来,Magento的EAV性能是一个真正的难题。

这就是为什么我倾向于使用归一化结构。为了克服缺乏灵活性,我考虑在未来添加一些单独的数据字典(XML或单独的DB表),可以进行编辑,并基于此生成用于显示和比较具有新属性集的产品类别的应用程序代码,以及SQL脚本。

这种架构似乎是这种情况下的最佳选择-既灵活又高效。

问题可能是在实时环境中频繁使用ALTER TABLE。我正在使用Postgres,因此其MVCC和事务DDL将有望减轻痛苦。


3
如果仅涉及产品目录属性,因此对这些属性的验证要求相当有限,那么EAV模型唯一的真正缺点是查询性能,即使在查询处理多个带属性的“物品”(产品)时,性能也只是一个问题,“给我ID为234的产品的所有属性”这个查询的性能虽然不是最优的,但仍然足够快。
其中一个解决方案是仅将SQL数据库/EAV模型用于产品目录的管理/编辑方面,并有一些流程将产品非规范化为可搜索的内容。由于您已经拥有属性并且很可能想要分面,因此这种东西可以是Solr或ElasticSearch。这种方法避免了EAV模型的所有缺点,而增加的复杂性仅限于在更新时将完整产品序列化为JSON。

2
我认为在EAV中最好采用最低有意义的原子级建模。让面向特定用户群体的标准、技术和应用程序来决定内容模型、属性重复需求、颗粒度等。请注意保留HTML标签,不要添加解释。

2

EAV存在很多缺点:

  1. 随着应用程序中数据量的增长,性能会逐渐下降。一旦数据量超过一定大小,检索和处理数据就可能变得越来越低效。
  2. SQL查询非常复杂且难以编写。
  3. 数据完整性问题。您无法为所有所需字段定义外键。
  4. 您必须定义和维护自己的元数据。

  1. 这对于大多数关系型数据库也是正确的;这就是为什么分片被发明的原因。
  2. 数据建模可能会很复杂,难以实现。我曾经花费了几周甚至几个月的时间等待OLAP立方体模式的更改。
  3. 现在已经大部分在软件中完成了。
  4. 当建模关系模式时,您无论如何都必须在ERwin、Excel和Visio中进行此操作。
- cowbert
@cowbert:当然。EAV性能比标准化架构下降得更快,即缩放更差。举个例子,请查看这篇论文:https://www.ncbi.nlm.nih.gov/pmc/articles/PMC79043/。 - Joel Mellon

1
我有一个略微不同的问题:与稀疏值的许多属性不同(这可能是使用EAV的好理由),我想存储更像电子表格的东西。表中的列可以更改,但在表内所有单元格都将包含数据(不是稀疏的)。
我制作了一组小测试以对比两种设计的性能:一种使用EAV,另一种使用Postgres ARRAY存储单元格数据。 EAVenter image description here Arrayenter image description here 两种模式都在适当的列上具有索引,并且规划器使用这些索引。
结果显示,基于数组的模式在插入和查询方面快了一个数量级。从快速测试来看,似乎两者都呈线性扩展。不过测试并不十分彻底,欢迎提出建议和派生 - 它们都是在MIT许可下发布的。

你是如何在表格列上进行连接(即vlookup)与数组模型?难道不需要编写自己的数组合并排序函数吗?如果您使用单元格的sheet_id + x坐标+y坐标作为单元格值的键,则高度怀疑它能否像预编译的合并排序一样好。(为了模拟Excel,预先生成一个x坐标的查找表,其中0-18278是A-ZZZ列(Excel最大为16384),然后您可以选择其中sheet_id = uuid且x-coord = 0且y-coord <1001的值以获取前1000行A列。 - cowbert
@cowbert 你说得对;实际上,我只是加载我感兴趣的列,并在Python中进行连接。太棒了! - z0r

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