股票系统的EAV模型方案还是不同的方法?

ros*_*hai 4 php mysql sql entity-attribute-value

我正在使用关系数据库(MySQL)和PHP开发库存和仓库管理系统.由于库存产品将具有多种特征(宽度,高度,重量,尺寸,颜色等),因此需要采用数据库模型方法来存储属性以及添加/编辑新属性的可能性,产品类型等.所以,在目前的概念中我只能看到3个可行的模型:

  1. 将所有属性存储在单个表中,作为分隔列并基于产品类型(可能是类别)将它们提供给最终用户来填充
  2. EAV(实体 - 属性 - 价值)模型将包含以下内容:
    • 包含属性类的类别表
    • 一类属性表,它将包含具有多个属性的单独类(以这种方式,我们确保我们可以向类别添加一类属性,而无需一个接一个地手动添加到类似的类别属性)
    • 属性表负责属性本身
    • 我们存储值的属性值表
  3. 将所有公共属性存储在单个表中,并为所有不同类别类型创建多个表:每次遇到新类别类型时,此模型都需要更改数据库

第二个模型的灵感来自于此.

在阅读了很多关于EAV模型的内容之后,我现在对这个模型产生了怀疑,我对如何在订单/发票中连接不同的产品属性等方面几乎没有关注.即使表单的验证似乎也是如此使用EAV模型的真正痛苦,但仍然..我不希望有一个包含100多列的单个表,然后准备好在每次添加新属性时添加新列.

所以,问题是:是否有更便宜的解决方案?或者EAV模型可以改进吗?

我知道这是一个漫长而古老的争论,但每个人都只是指向NoSQL而我只依赖于RDBMS.

编辑:

这些方法(或大多数方法)的缺点是:

  • 对于指定的属性,可能应该存在一个度量单位(eq.属性权重应该包含测量单位的下拉列表)
  • 指定的属性应该是强制的
  • 所有属性都应该对表单提交进行验证

到目前为止,唯一可行的解​​决方案是为每个新类别创建一个新表,并在该表中处理所有自定义属性和规则.但是,再一次,当一个新的类别被建立时,它将最终成为一个真正的痛苦.

编辑2:

在MySQL中使用Json列的选项,并没有从我的角度解决上面提到的任何缺点..或者,也许我错了,我不清楚看到大图..

Con*_*one 6

我认为这些是您的主要要求:

  1. 灵活的属性
    • 您在此处的确切需求尚不清楚:听起来您希望属性发生变化,或者至少期望所有属性并不总是适用于所有产品(即稀疏矩阵)
  2. 产品也被分类,类别将(至少部分地)确定适用于产品的属性
  3. 除了值之外,属性本身可能还有其他属性,必须由用户提供(即带有权重的单位)
  4. 输入验证是必须的,并检查以下内容:
    • 存在所有必需属性
    • 不存在不适用的属性
    • 属性具有有效值
    • 用户提供的属性属性具有有效值
  5. 您可能还希望确保可以按属性进行有效搜索/过滤

这些不同的要求都会导致不同的技术需求和不同的技术解决方案.有些是数据库的问题,有些必须在代码中解决,无论数据库选择如何.显然你已经意识到其中的一些问题,但我认为值得真正分解:

灵活的属性

拥有灵活属性列表(如您所知)不适用于必须预定义表模式的RDBMS系统.这包括几乎所有的SQL,绝对是MySQL.问题是更改表模式是昂贵的,对于大型表可能需要几分钟或几小时,如果您必须向表中添加列来执行此操作,则几乎不可能添加属性.

即使您的属性列表很少更改,如果大多数产品没有大多数属性的值(即稀疏矩阵),则大型属性表效率非常低.

从长远来看,如果您的属性作为表中的列存储,您将无法到达任何地方.即使你按类别细分,你仍然会有大的空表,你无法动态地添加列.

如果您坚持使用RDBMS,您唯一的选择就是EAV系统.在考虑,研究和实施EAV系统后,我不会太担心你在互联网上听到的所有炒作.我知道有很多文章在谈论EAV"反模式",我是那种认真对待软件设计模式的人,但EAV确实有一个完全有效的时间和地点,就是这个.从长远来看,如果没有EAV,您将无法在RDBMS上执行此操作.您当然可以查看针对此特定类型问题而设计的NoSQL系统,但是当数据库的其余部分位于标准RDBMS中时,安装或切换到NoSQL系统只是为了存储属性值几乎肯定是矫枉过正.您当然不希望失去RDMBS附带的ACID合规性,并且大多数NoSQL系统不保证ACID合规性.有一系列的NewSQL系统旨在充分利用两个世界,但如果这只是一个更大的应用程序的一部分(我确信是这样),它可能不值得完全调查新技术只是为了实现这一功能.您还可以考虑使用MySQL内部的JSON存储来存储属性值.这是一个可行的选择,因为MySQL有更好的JSON支持,但这只会对整体情况做一个小改动:你仍然需要所有其他EAV表来跟踪允许的属性,类别等.它只是属性您可以放在JSON数据中的值,因此JSON存储的潜在好处相对较小(并且还有其他问题,我将在后面提到).

总而言之,我想说只要应用程序的其余部分在RDBMS上运行,使用EAV管理灵活属性是完全合理的.如果你试图在RDBMS内部的EAV中构建整个系统,那么你肯定会浪费你的时间,我会告诉你去找一个适合你试图解决的问题的NoSQL数据库.EAV的缺点仍然适用:您无法在RDBMS系统中轻松执行一致性检查,并且必须自己在代码中执行此操作.

具有类别特定属性的分类产品

你已经在这里得到了它.这在EAV系统内部相对简单.您将拥有属性表,您将拥有一个类别表,然后您将需要属性和类别表之间的标准一对多或多对多关系,这将确定哪些属性可用于哪个类别.您显然也有产品和类别之间的关系,因此您知道哪些产品需要哪些属性.

您的选项#3旨在满足此要求,但是随着系统的增长,将每个属性作为列的表将会非常糟糕,如果您需要动态添加属性,它肯定会中断.您不希望动态运行ALTER TABLE语句,尤其是如果您有超过几千条记录.

管理属性属性

存储动态属性和值是一回事.另一个问题是完全存储动态属性,值和关联的元数据(即存储权重以及权重所在的单位).然而,这不再是数据库问题,而是代码问题.在实际存储信息方面,您最好的选择是将元数据存储在属性值表中,并依赖一些代码抽象来处理输入验证以及表单构建.这可能会非常复杂,特别是如果做错了,通过这样的系统进行交谈会需要另外一个完整的帖子.但是,我认为你是在正确的轨道上:对于需要值和元数据的更高级属性,你需要以某种方式分配一个负责输入处理和表单验证的类.例如,对于一个简单的文本字段,您有一个"text"类,它从表单中读取用户的值,并将其存储在正确的"attribute_values"表中,而不存储元数据.然后,对于您的"权重"属性,您将拥有一个"权重"属性,用于存储用户给出的数字(即0.5),但随后还会存储用户使用该数字指定的单位(即"lbs"),并将两者都保存到"ATTRIBUTE_VALUES"表(伪SQL) INSERT INTO attribute_values value='0.5', meta_data='{"unit":"lbs"}', product_id=X, attribute_id=X.具有讽刺意味的是,JSON可能是存储此元数据的好方法,因为保留的确切元数据也会因属性类型而异,我怀疑您是否需要另一级别的表来处理EAV表中的变化.

同样,这更多的是代码问题,而不是存储问题.如果你决定做JSON表,那么满足这个要求的整体图片就不会改变:你的"属性类型"只会以不同的方式存储元数据.这可能看起来像:UPDATE products SET attributes='{"weight":0.5,"unit":"lbs"}' WHERE id=X

输入验证

无论您如何存储数据,都必须由代码专门处理,因此在决定数据库结构方面,此要求无关紧要.如果正确执行,如上所述的基于类的系统也将能够处理输入验证.

排序/搜索/过滤器

如果您专门使用属性进行数据存储/检索,这无关紧要,但您是否会搜索属性?使用适当的EAV系统和良好的索引,您实际上可以在RDBMS系统中有效地进行搜索/排序(尽管如果您一次搜索多个索引,就会开始变得痛苦).我没有仔细查看,但我很确定使用JSON存储在搜索方面不能很好地扩展.虽然MySQL 现在可以使用JSON并直接搜索列,但我非常怀疑这种搜索/排序是否使用了MySQL索引,这意味着它不适用于大型数据库.不过我可能错了.如果您打算做类似的事情,那么在提交MySQL/JSON存储设置之前,值得深入研究.

根据您的需求,这也是使用NoSQL系统来补充RDBMS系统的好地方.之前管理过大型(约150万个产品)的电子商务系统,我发现MySQL在搜索/排序类别中往往趋于平缓,特别是如果您正在进行任何类型的文本搜索.在电子商务系统中,如下所示的查询:"向我显示最符合术语'蓝色卡车'并且具有'适用于3-5岁'的属性"的结果很常见,但在MySQL中执行类似的操作几乎是不可能的,主要是因为需要基于相关性的排序和评分.我们通过使用Apache Solr实现解决了这个问题(弹性是类似的解决方案),并管理我们的搜索/排序/搜索项的得分非常好.在这种情况下,它是一个双数据库解决方案.MySQL将所有实际数据和存储属性保存在EAV表中,随时更新内容我们将所有内容的记录推送到Apache Solr以获得额外的存储空间.当一个查询来自用户时,我们会查询Apache Solr,它是文本搜索的专家,也可以毫无问题地处理属性过滤,然后我们将从MySQL数据库中提取完整的产品记录.该系统运行良好.我们拥有150万个产品,数千个自定义属性,并且可以轻松地从单个虚拟服务器上运行整个产品.很明显,幕后有很多代码,但重点是它确实有效并且不难维护.从来没有MySQL或Solr的性能问题.