我正在使用关系数据库(MySQL)和PHP开发库存和仓库管理系统。由于库存产品将具有多种特征(宽度,高度,重量,尺寸,颜色等),因此需要采用数据库模型方法来存储属性以及添加/编辑新属性的可能性,产品类型等。 因此,在目前的概念中,我只能看到3个可行的模型:
第二个模型的灵感来自here。
在阅读了很多关于EAV模型的内容之后,我现在对这个模型产生了怀疑,我对如何在订单/发票中连接不同的产品属性等方面几乎没有关注。即使表格的验证似乎也是如此这将是使用EAV模型的真正痛苦,但仍然..我不希望有一个包含100多列的单个表,然后准备在每次添加新属性时添加新列。< / p>
所以,问题是:是否有更便宜的解决方案?或者EAV模型可以改进吗?
我知道这是一场漫长而古老的辩论,但每个人都只是指着NoSQL而我只依赖于RDBMS ..
编辑:
这些方法(或大多数方法)的缺点是:
到目前为止,唯一可行的解决方案是为每个新类别创建一个新表,并在该表中处理所有自定义属性和规则。但是,再一次,当一个新的类别被建立时,它将最终成为一个真正的痛苦。
编辑2:
在MySQL中使用Json列的选项,从我的角度来看并没有解决上面提到的任何缺点..或者,也许我错了,我没有清楚地看到大图..
答案 0 :(得分:6)
我认为这些是您的主要要求:
这些不同的要求都会导致不同的技术需求和不同的技术解决方案。有些是数据库的问题,有些必须在代码中解决,无论数据库选择如何。显然你已经意识到其中的一些问题,但我认为值得真正分解:
灵活属性
拥有灵活属性列表(如您所知)对于必须预定义表模式的RDBMS系统不能很好地工作。这包括几乎所有的SQL,绝对是MySQL。问题是更改表模式是昂贵的,对于大型表可能需要几分钟或几小时,如果您必须向表中添加列来执行此操作,则几乎不可能添加属性。
即使您的属性列表很少发生变化,如果大多数产品都没有大多数属性的值(即稀疏矩阵),那么大型属性表效率非常低。
从长远来看,如果您的属性作为表中的列存储,您就无法获得任何结果。即使你按类别细分,你仍然会有大的空表,你不能动态地添加列。
如果您坚持使用RDBMS,您唯一的选择就是EAV系统。在考虑,研究和实施EAV系统之后,我不会过分担心您在互联网上听到的所有炒作。我知道有很多文章在谈论EAV&#34;反模式&#34;以及我认真对待那些正确使用软件设计模式的人,但是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语句,特别是如果您有超过几千条记录。
管理属性属性
存储动态属性和值是一回事。另一个问题是完全存储动态属性,值和相关的元数据(即存储权重以及权重所在的单位)。然而,这不再是数据库问题,而是代码问题。在实际存储信息方面,您最好的选择是将元数据存储在属性值表中,并依赖一些代码抽象来处理输入验证以及表单构建。这可能会非常复杂,特别是如果做错了,通过这样的系统进行交谈将需要另外一个完整的帖子。但是,我认为你是在正确的轨道上:对于需要值和元数据的更高级属性,你需要以某种方式分配一个负责输入处理和表单验证的类。例如,对于一个简单的文本字段,你有一个&#34; text&#34;从表单中读取用户值的类,并将其存储在正确的&#34; attribute_values&#34;表,没有存储元数据。然后为你的体重&#34;属性你会有一个&#34;重量&#34;存储用户给出的数字的属性(即0.5),但是也存储用户用该数字指定的单位(即&#39; lbs&#39;)并且将两者都保存到&#34; attribute_values&#34; table(在伪SQL中):INSERT INTO attribute_values value='0.5', meta_data='{"unit":"lbs"}', product_id=X, attribute_id=X
。具有讽刺意味的是,JSON可能是存储此元数据的好方法,因为保留的确切元数据也会因属性类型而异,我怀疑您是否需要另一级别的表来处理EAV表中的变化。
同样,这更多的是代码问题,而不是存储问题。如果你决定做JSON表,那么满足这个要求的整体图片就不会改变:你的&#34;属性类型&#34;只会以不同的方式存储元数据。这可能看起来像:UPDATE products SET attributes='{"weight":0.5,"unit":"lbs"}' WHERE id=X
输入验证
无论您如何存储数据,都必须由代码专门处理,因此在决定数据库结构方面,此要求并不重要。如果正确执行,如上所述的基于类的系统也将能够处理输入验证。
<强>排序/搜索/过滤强>
如果您专门使用属性进行数据存储/检索,这并不重要,但是您是否会搜索属性?使用适当的EAV系统和良好的索引,您实际上可以在RDBMS系统中有效地进行搜索/排序(尽管如果您一次搜索多个索引,就会开始变得痛苦)。我没有仔细查看,但我非常确定使用JSON存储在搜索时不会很好地扩展。虽然MySQL 可以现在使用JSON并直接搜索列,但我非常怀疑这种搜索/排序是否使用了MySQL索引,这意味着它不能使用大型数据库。不过我可能错了。在提交MySQL / JSON存储设置之前,如果您要做类似的事情,那么值得深入研究。
根据您的需求,这也是使用NoSQL系统补充RDBMS系统的好地方。之前管理过大型(约150万个产品)的电子商务系统,我发现MySQL在搜索/排序类别中往往趋于平缓,尤其是如果您正在进行任何类型的文本搜索。在电子商务系统中,查询类似于:&#34;向我显示最符合术语“蓝卡车”的结果。并具有属性&#39;对于3-5岁及以上的人来说&#34;很常见,但在MySQL中做类似的事情是不可能的,主要是因为需要基于相关性的排序和评分。我们通过使用Apache Solr解决了这个问题(Elastic是一个类似的解决方案),它管理我们的搜索/排序/搜索术语得分非常。在这种情况下,它是一个双数据库解决方案。 MySQL将所有实际数据和存储属性保存在EAV表中,随时更新内容我们将所有内容的记录推送到Apache Solr以获得额外的存储空间。当一个查询来自用户时,我们会查询Apache Solr,它是文本搜索的专家,也可以毫无问题地处理属性过滤,然后我们将从MySQL数据库中提取完整的产品记录。该系统运行良好。我们拥有150万个产品,数千个自定义属性,并且可以轻松地从单个虚拟服务器上运行整个产品。很明显,幕后有很多代码,但重点是它确实有效,并且难以维护。从来没有任何MySQL或Solr的性能问题。
答案 1 :(得分:2)
嗯,这只是一种方法。如果您不需要或不想要所有这些,可以简化这一过程。
例如,您可以使用Json column in Mysql来存储所有额外属性。另一个想法,在产品类型中,添加一个json列来存储自定义属性和类型,并使用它来在屏幕上绘制表单。
答案 2 :(得分:2)
我建议您首先浏览一个EAV数据库,以便了解数据库创建和数据库。它的价值观。
您可以使用使用EAV模型的magento DB结构。
EAV代表实体属性和价值模型。让我们仔细看看所有部分。
实体:数据项表示为实体,可以是产品或客户或类别。在数据库中,每个实体都有一条记录。
属性:这些属于不同的实体,例如,Customer实体具有Name,Age,Address等属性。在Magento数据库中,所有属性都列在单个表中。
值:只需要属性的值,例如Name属性的值就是“Rajat”。
当您拥有实体的许多属性且这些属性是动态的(添加/删除)时,将使用EAV。 此外,很有可能这些属性中的许多在大多数情况下都具有空值或空值。 在这种情况下,EAV结构具有许多优点,主要是优化的mysql存储
对于您的案例 - 类别也可以具有属性,产品也可以具有客户等属性......
我们来看一个类别的例子。以下是magento提供的表格:
1. catalog_category_entity
2. catalog_category_entity_datetime
3. catalog_category_entity_decimal
4. catalog_category_entity_int
5. catalog_category_entity_text
6. catalog_category_entity_varchar
7. catalog_category_flat
点击此链接了解有关表格的更多信息
对于属于选择框的属性。您可以将下拉值放在选项值下。
按照此链接了解magento eav结构,它将为您提供有关EAV模型如何工作的清晰图片。如何充分利用它。
答案 3 :(得分:0)
如果您想坚持使用关系数据库,有三种方法。
如果您事先知道所有产品的属性,那么第一个是最好的。您选择three ways之一来存储关系模型中的多态数据。
从关系的角度看它是“干净的” - 你只是使用行和列,但3个选项中的每一个都有其自身的优点和缺点。
如果您在开发时不知道自己的属性,我建议不要使用这些解决方案 - 它们需要大量额外的工具。
下一个选项是EAV。好处和缺点都有详细记录 - 但您对“验证输入表单”的关注只是数据的一个用例,我认为您可以轻松地发现您的数据变为“只写”。例如,提供排序/过滤变得非常困难(“找到所有高度至少为12的产品,并按材料类型排序”几乎不可能使用EAV模型)。
我更喜欢的选项是核心的关系数据,不变数据和变量数据的以文档为中心(JSON / XML)的组合。 MySQL可以本地查询JSON - 因此您可以按变量属性进行排序/过滤。但是,您必须创建自己的验证逻辑 - 可能通过在数据输入应用程序中集成JSON Schema。
通过使用JSON Schema,您可以引入“属于一起”的概念,并提供查找值。例如,如果您有产品重量,您的模式可能会说重量总是必须有一个度量单位,有效选项是千克,毫克,盎司,磅等。
如果变量数据中存在外键关系,则表示存在问题 - 例如,“manufacturer”可能链接到制造商表。您可以将其建模为显式列,也可以在JSON中进行建模,不使用SQL的内置外键工具(如连接)。