ros*_*hai 4 php mysql sql entity-attribute-value
我正在使用关系数据库(MySQL)和PHP开发库存和仓库管理系统.由于库存产品将具有多种特征(宽度,高度,重量,尺寸,颜色等),因此需要采用数据库模型方法来存储属性以及添加/编辑新属性的可能性,产品类型等.所以,在目前的概念中我只能看到3个可行的模型:
第二个模型的灵感来自于此.
在阅读了很多关于EAV模型的内容之后,我现在对这个模型产生了怀疑,我对如何在订单/发票中连接不同的产品属性等方面几乎没有关注.即使表单的验证似乎也是如此使用EAV模型的真正痛苦,但仍然..我不希望有一个包含100多列的单个表,然后准备好在每次添加新属性时添加新列.
所以,问题是:是否有更便宜的解决方案?或者EAV模型可以改进吗?
我知道这是一个漫长而古老的争论,但每个人都只是指向NoSQL而我只依赖于RDBMS.
编辑:
这些方法(或大多数方法)的缺点是:
到目前为止,唯一可行的解决方案是为每个新类别创建一个新表,并在该表中处理所有自定义属性和规则.但是,再一次,当一个新的类别被建立时,它将最终成为一个真正的痛苦.
编辑2:
在MySQL中使用Json列的选项,并没有从我的角度解决上面提到的任何缺点..或者,也许我错了,我不清楚看到大图..
我认为这些是您的主要要求:
这些不同的要求都会导致不同的技术需求和不同的技术解决方案.有些是数据库的问题,有些必须在代码中解决,无论数据库选择如何.显然你已经意识到其中的一些问题,但我认为值得真正分解:
灵活的属性
拥有灵活属性列表(如您所知)不适用于必须预定义表模式的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的性能问题.