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

Posted

技术标签:

【中文标题】实体属性值数据库与严格的关系模型电子商务【英文标题】:Entity Attribute Value Database vs. strict Relational Model Ecommerce 【发布时间】:2010-10-26 15:05:29 【问题描述】:

可以肯定地说EAV/CR 数据库模型很糟糕。也就是说,

问题:应该使用什么数据库模型、技术或模式来处理描述电子商务产品的属性“类”,这些属性可以在运行时更改?

在一个好的电子商务数据库中,您将存储选项类别(例如电视分辨率,然后为每台电视设置一个分辨率,但下一个产品可能不是电视,也没有“电视分辨率”)。您如何存储它们、有效搜索并允许您的用户使用描述其产品的可变字段设置产品类型?如果搜索引擎发现客户通常根据控制台深度搜索电视,您可以将控制台深度添加到您的字段中,然后在运行时为每种电视产品类型添加一个深度。

优秀的电子商务应用有一个很好的共同特征,它们会显示一组产品,然后有“向下钻取”侧边菜单,您可以在其中看到“电视分辨率”作为标题,以及最常见的前五名电视搜索结果的分辨率。您单击一个,它只显示该分辨率的电视,允许您通过选择侧面菜单上的其他类别进一步深入研究。这些选项将是在运行时添加的动态产品属性。

进一步讨论:

长话短说,互联网上是否有任何链接或模型描述可以“从学术上”解决以下设置?我感谢 Noel Kennedy 提出了一个类别表,但可能需要大于那个。我在下面用不同的方式描述它,试图突出它的重要性。我可能需要更正视点来解决问题,或者我可能需要更深入地了解 EAV/CR。

喜欢对 EAV/CR 模型的积极响应。我的开发人员同事都说 Jeffrey Kemp 在下面谈到的内容:“新实体必须由专业人士建模和设计”(断章取意,请阅读下面的回复)。问题是:

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

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

部门/关键词搜索/同类产品对比图 结帐前的消费者产品配置

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

【问题讨论】:

为什么不能有一个“类别”表,外键引用它自己? 说 EAV 数据库模型不好并不安全,也不准确,因为它非常适合某些应用程序。 如果你用各种属性装饰各种对象,像在 Entity Framework 4 中那样从父对象继承呢?它如何持久化这些对象? 回到这篇优秀的文章,该文章讲述了一位顾问使用基于extreme 版本EAV 的系统的经验。阅读! simple-talk.com/opinion/opinion-pieces/bad-carma EAV 是一种非常可行的数据库模型。我正在解决与您类似的问题,解决方案是 EAV。我会推荐以下文章:sqlblog.com/blogs/aaron_bertrand/archive/2009/11/19/… 【参考方案1】:

我有一个稍微不同的问题:我想存储一些更像电子表格的东西,而不是许多具有稀疏值的属性(这可能是使用 EAV 的一个很好的理由)。工作表中的列可以更改,但在工作表中,所有单元格都将包含数据(不是稀疏的)。

我创建了一个small set of tests 来对两种设计进行基准测试:一种使用 EAV,另一种使用 Postgres ARRAY 来存储单元格数据。

EAV

数组

两种模式在适当的列上都有索引,并且索引由规划器使用。

原来array-based schema was an order of magnitude faster 用于插入和查询。从快速测试来看,两者似乎都是线性缩放的。不过,测试不是很彻底。欢迎提出建议和分叉 - 它们受 MIT 许可。

【讨论】:

您是如何使用数组模型在工作表列(即 vlookup)上进行连接的?您不必编写自己的数组合并排序函数吗?如果您使用单元格的 sheet_id + x 坐标 + y 坐标作为单元格值的键,则高度怀疑它是否可以与预编译的合并排序一样好。 (要模拟 excel,为 x 坐标预先生成一个查找表,其中 0-18278 是 A-ZZZ 列(excel 在 16384 处最大)),然后您可以选择 sheet_id=uuid 和 x-coord = 0 和 y-coord 的值 @cowbert 你是对的;实际上我只是加载我感兴趣的列并在 Python 中进行连接。松懈!【参考方案2】:

EAV 有很多缺点:

    随着时间的推移性能下降 一旦应用程序中的数据量增长到超过一定大小,该数据的检索和操作可能会变得越来越低效。 SQL 查询非常复杂且难以编写。 数据完整性问题。 您不能为所有需要的字段定义外键。 您必须定义和维护自己的元数据。

【讨论】:

1.大多数关系数据库也是如此。这就是发明分片的原因。 2. 数据建模可能很复杂且难以实施。我花了数周数月的时间等待 OLAP 多维数据集架构更改。 3. 现在大部分都在软件中完成 4. 在对关系模式进行建模时,您必须“在 ERwin、Excel 和 Visio 中”执行此操作。【参考方案3】:

如果它只是关于产品目录属性,因此对这些属性的验证要求相当有限,EAV 唯一真正的缺点是查询性能,即使这只是当您的查询处理多个“事物”(产品)时才会出现问题对于属性,查询“给我 ID 为 234 的产品的所有属性”的性能虽然不是最佳的,但仍然很快。

一种解决方案是仅将 SQL 数据库/EAV 模型用于产品目录的管理/编辑端,并通过一些流程将产品非规范化为使其可搜索的内容。由于您已经拥有属性,因此您很可能想要分面,这可能是 Solr 或 ElasticSearch。这种方法基本上避免了 EAV 模型的所有缺点,并且增加的复杂性仅限于在更新时将完整的产品序列化为 JSON。

【讨论】:

【参考方案4】:

我能想到一些一般的优点和缺点,在某些情况下,一种比另一种更好:

选项 1,EAV 模型:

专业版:设计和开发简单应用程序的时间更少 专业版:易于添加的新实体(甚至可能 由用户添加?) 专业版:“通用”界面组件 缺点:验证简单数据类型所需的复杂代码 Con:更复杂的 SQL 更简单 报告 Con:复杂的报表几乎可以变成 不可能 缺点:大型数据集性能不佳

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

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

选项 3,组合(“正确”模型实体,但为部分/所有实体的自定义属性添加“扩展”)

赞成/反对:收集需求和设计所需的时间比选项 1 多,但可能不如选项 2 * 缺点:新实体必须由专业人士建模和设计 专业人士:以后可能会轻松添加新属性 缺点:验证简单数据类型所需的复杂代码(用于自定义属性) 缺点:仍然需要自定义界面组件,但自定义属性可能会使用通用界面组件 缺点:只要报告中包含任何自定义属性,SQL 就会变得复杂 缺点:一般性能良好,除非您开始需要按自定义属性搜索或报告

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

我个人倾向于选项 2,并尽可能避免 EAV。但是,对于某些场景,用户需要 EAV 带来的灵活性;但这需要付出很大的代价。

【讨论】:

如果您有一个包含文本值 1-n 索引的单个表,然后在 C#(在 ram 中)将您想要的内容映射到您需要的内容。它仍然可以像 EAV 一样工作,但“匹配”将是域模型。有点像序列化,但您可以在索引文本字段上使用 SQL 选择。每条记录没有多重选择。所有的“成本”都发生在 RAM 中。 @Zim,这听起来很像选项 3。每行有 1-n 个额外的“通用”列,并且存储在其中的数据在应用程序级别进行解释。您可以获得将一条记录的所有数据放在一个位置的性能优势。然而,关于这些列的元数据需要存储在某个地方,而这正是成本上升的地方。当然,我们可以将元数据缓存在 ram 中,但它仍然比直接在应用程序代码中建模域的成本更高。当然比成熟的 EAV 模型更好! +10000 很好的答案。如今,人们在数据库设计和需求收集方面略显吝啬。他们宁愿写一百倍以上的代码,花时间做出好的设计。 如果您只提供选项 1 的结构,则关系选项 (2) 不需要比 EAV 选项 (1) 进行 更多 设计。关系接口是描述该结构的元数据的通用接口。这将删除所有选项 2 缺点。但是您忘记了唯一实际的缺点:DDL 管理表可能太慢了。 嗨@philipxy,我没有说“更多设计”。 EAV 存在的理由是(大概)系统设计师可以在设计模型上花费更少的时间,然后将这项设计工作留给“用户”(这种缺乏专业设计导致为选项 1 列出的缺点)。如果 EAV 没有为设计人员节省成本,那只会为拒绝 EAV 失控而火上浇油。另外,我不同意 DDL“太慢”——因为它应该很少需要(即修复模型中的错误或实现新功能),它的性能应该相对不重要。【参考方案5】:

在性能不是主要要求的情况下,例如在 ETL 类型的应用程序中,EAV 具有另一个明显的优势:差异保存。

我已经实现了许多应用程序,其中最重要的要求是能够查看域对象从其第一个“版本”到当前状态的历史记录。如果该域对象具有大量属性,则意味着每次更改都需要将新行插入到其对应的表中(不是更新,因为历史记录会丢失,而是插入)。假设这个域对象是一个 Person,我有 500k Persons 要跟踪,在 Persons 生命周期中平均有 100 多个更改为各种属性。再加上只有 1 个主要领域对象的应用程序很少见,您很快就会推测数据库的大小会迅速失控。

一个简单的解决方案是只保存对主要域对象的差异更改,而不是重复保存冗余信息。

所有模型都会随着时间的推移而变化,以反映新的业务需求。时期。使用 EAV 只是我们使用的工具之一;但它绝不应该被自动归类为“坏”。

【讨论】:

+1 表示“使用 EAV 只是我们要使用的工具之一;但它永远不应该被自动归类为“坏”。” 顺便说一句,这被称为 SCD(缓慢变化的尺寸)。此外,具有此属性的属性的双时态要求(类型 4 SCD 的特定情况)需要 EAV 模式。请记住,99% 的 NoSQL 没有原生连接,因此如果您需要对此类数据进行“实时”连接,EAV 是唯一的选择。【参考方案6】:

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

我从未在生产环境中练习过 NoSQL(刚刚测试了 MongoDB 并印象深刻),但 NoSQL 的重点在于能够将具有不同属性的项目保存在同一个“文档”中。

【讨论】:

考虑写入 MongoDB 需要数据库级锁定,这对并发生产流量意味着什么。 考虑锁定持续时间以微秒为单位。【参考方案7】: // 在这一点上,我想花点时间和你谈谈 Magento/Adobe PSD 格式。 // Magento/PSD 不是一个好的电子商务平台/格式。 Magento/PSD 甚至不是一个糟糕的电子商务平台/格式。这么称呼它 // 侮辱其他不良电子商务平台/格式,例如 Zencart 或 OsCommerce。不,Magento/PSD 是一个糟糕的电子商务平台/格式。有 // 这段代码已经工作了好几个星期了,我对 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:

    你得到了一大袋钱 你必须 享受痛苦

【讨论】:

这是一篇较旧的帖子,但我希望我在 3 个月前为客户启动 Magento 项目时找到了这个。为 boggle/paint-shaker 类比 +1! 非常有趣,magento 似乎是电子商务系统的王者。也许只是它的营销非常好 Magento 不受欢迎是因为维护级别高,但可以自定义,允许任何人在不改变架构或少量修改的情况下实现新功能。此功能需要付费。 如果您想避免 FE 和 BE 的三重痛苦和更多痛苦,请远离 Magento 2【参考方案8】:

我仍然投票支持在 EAV 的最低意义原子级别建模。让面向特定用户社区的标准、技术和应用程序来决定内容模型、属性的重复需求、粒度等。

【讨论】:

【参考方案9】:

我正在努力解决同样的问题。您可能会感兴趣查看以下关于两个现有电子商务解决方案的讨论:Magento (EAV) 和 Joomla(常规关系结构): https://forum.virtuemart.net/index.php?topic=58686.0

看来,Magento 的 EAV 性能是真正的亮点。

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

在这种情况下,这种架构似乎是最佳选择 - 同时具有灵活性和高性能。

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

【讨论】:

【参考方案10】:

可以肯定地说 EAV/CR 数据库模型很糟糕。

不,不是。只是它们对关系数据库的使用效率低下。纯键/值存储非常适合此模型。

现在,你真正的问题是:如何存储各种属性并保持它们可搜索?

只需使用 EAV。在您的情况下,它将是一张额外的桌子。在属性名称和值上都对其进行索引,大多数 RDBM 会对属性名称重复使用前缀压缩,使其非常快速和紧凑。

当您使用 EAV/CR 替换“真实”字段时,它会变得丑陋。与所有工具一样,过度使用它是“不好的”,并且会给它带来不好的形象。

【讨论】:

所以问题是我的一个类别有 15 个附加字段,并且在 eav 模型中它需要 16 个连接 + 主表,因此需要 16 个左连接来搜索产品(如果客户想要的话,有 16 个)在 3-4 百万条记录中(一个人们出售二手产品的网站),所以它的性能很低? 如果已经定义了这些“附加字段”,那么最好将其作为“真实字段”来完成。当然,在大型查询中执行无限数量的连接将是一个沉重的代价(但可能仍然可以!)。我在一个元数据繁重的项目中所做的是允许每个“主要项目”有任意数量的“标签”(作为 EAV 记录),但“大型查询”只选择一些预定义的标签名,保持连接总数有限(目前典型的是只有 4 个标签和大约 5 个其他连接),当用户选择一个特定的项目时,然后它会获取所有相关的东西,但对于单个项目。 当然,该特定系统目前正在移植到 hstore 字段(这只是我们使用 PostgreSQL 的原因之一)

以上是关于实体属性值数据库与严格的关系模型电子商务的主要内容,如果未能解决你的问题,请参考以下文章

关系数据库模式设计 - 如何直接从实体的字段集建模一对一映射

将 JSON 映射到数据模型,需要从动态键中获取嵌套的电子邮件值

在 Outlook 对象模型中哪里可以找到 mailitem 对象的属性值“电子邮件帐户”?

NSPredicate:“添加”一对多关系CoreData中所有实体的属性值

实体属性表的计算机科学中的实体属性表

从E-R模型到关系模型