SQL 与 NoSQL 用于添加多个过滤器后将呈现给用户的数据
Posted
技术标签:
【中文标题】SQL 与 NoSQL 用于添加多个过滤器后将呈现给用户的数据【英文标题】:SQL vs NoSQL for data that will be presented to a user after multiple filters have been added 【发布时间】:2013-10-27 19:48:54 【问题描述】:我即将开始一个非常超出我正常职责范围的工作项目。作为一名 SQL DBA,我最初的倾向是使用 SQL 数据库来处理项目,但我对 NoSQL 了解得越多,我就越相信它可能是更好的选择。我希望我可以使用这个问题来概括地描述这个项目,以获得关于使用每个选项的利弊的一些反馈。
该项目相对简单。我有一组具有各种属性的对象。其中一些属性对所有对象都是通用的,而一些属性只对对象的子集通用。我的任务是构建一个服务,用户根据对象的属性选择一系列过滤器,然后返回与所有过滤器匹配的对象列表。当用户选择过滤器时,他或她可能正在过滤公共或子集属性,但在前端是抽象的。
^ 根据用户反馈,对象列表可能仅匹配某些过滤器,并且匹配的质量将通过分数显示给用户,该分数指示有多少标准匹配。
看过 Martin Folwler (http://www.youtube.com/watch?v=qI_g07C_Q5I) 的演讲后,文档样式的 NoSQL 数据库似乎应该适合我的需求,但鉴于我没有使用这种方法的经验,我也可能遗漏了一些东西明显的。
一些附加信息 - 数据库最初将有大约 5,000 个对象,每个对象包含 10 到 50 个属性,但对象的数量肯定会随着时间的推移而增加,并且属性的数量可能会根据用户反馈而增加。此外,我希望能够在收到用户反馈时对产品进行快速更改,因此灵活性非常重要。
非常感谢任何反馈,如果我在讨论中遗漏了任何重要内容,我很乐意提供更多信息。谢谢。
【问题讨论】:
5000 个对象在任何架构中似乎都过多......那是 5000 个表吗?您是否计划为每个客户提供一张桌子或其他什么?除非您能够为您找到/雇用专门的 NoSQL 资源,否则在这里边学习边学习似乎很痛苦……我建议您坚持使用您熟悉的内容来实现这种规模。 也许我在这里误用了术语。我所说的 5000 个对象是指 SQL 数据库中的 5000 行。 @Twelfth 我的澄清有意义吗? 是的,但我不确定 SQL 与 NOSQL 是否适合您。 5000 行对于数据库来说非常小,我想问你为什么要在这里走 NoSQL 路线。我认为具有名称值对子表的标题表将是最能处理动态属性的设置(也使添加新属性变得简单)。如果您愿意,可以更好地为您描述,但您必须熟悉 SQL 语法才能转出数据 @Twelfth 如果您能更好地描述一下,我将不胜感激。这似乎是我正在寻找的东西。关于为什么 NoSQL 用于这么小的数据库,我想说我的答案是双重的。首先,我喜欢动态添加属性并为单个对象拥有多个相似属性的能力,例如,Phone1、Phone2、Phone 3。其次,如果一切顺利,数据库的大小有可能会快速增长。跨度> 【参考方案1】:这个问题可以通过使用两种不同的技术来解决。第一个是使用设计相对良好的数据库模式和现代 RDBMS。通过使用通常的规范化原则对应用程序进行建模,您将从存储中获得非常好的单个 CRUD 语句响应。
正如您所猜测的那样,搜索此架构将是一场大规模的噩梦。不要这样做。而是考虑使用Solr/Lucene 作为您的全文搜索引擎。 Solr 对动态字段的支持意味着您可以动态地向文档/对象添加新属性,并且如果您正确设计了 Solr 架构,则可以立即在数据中进行搜索。
【讨论】:
感谢您的回复。您是否有理由避免采用其他答案中描述的 NoSQL 路线? 因为关系模型支持良好,所以您所说的规模级别可以由商业和开源 RDBMS 轻松处理,并且您可以避免使用 Solr 之类的搜索的痛苦。虽然我确实喜欢一些 NoSQL(我什至为了好玩而编写了一个数据库客户端),但除了最初的“只是将东西扔到文档中”的简单性之外,还存在潜在的开销。扩展可能不像您想象的那么简单,您会发现使用 RDBMS 比使用 NoSQL 解决方案更容易找到专家。 哦,EAV 模型无法在 RDBMS 中扩展。在你用完可用内存之前它会做得很好,然后它会迅速触底。你可以在一段时间内用金钱来扩大规模,但最终你会遇到一个限制。 @zgall1 - Jeremiah 的回声:“你会发现使用 RDBMS 比使用 NoSQL 解决方案更容易找到专家”NoSQL 还很年轻,它的专业知识仍在开发中......使寻找支持和资源变得更具挑战性。此处应在您的决定中考虑 NoSQL 资源的可用性【参考方案2】:不妨把这个作为答案。我应该说我在 NoSQL 方面并不强,所以我倾向于使用 SQL。
我会以三张桌子的形式来做这件事。您将在网络上看到它被称为实体值对逻辑......这是一种处理项目的多个动态属性的方法。假设您有一堆产品,每个产品都有一些属性。
Prd 1 - a,b,c
Prd 2 - a,d,e,f
Prd 3 - a,b,d,g
Prd 4 - a,c,d,e,f
所以这里有 4 种产品和 6 种属性...同样的理论适用于数百种产品和数千种属性。将其保存在一个表中的标准方法需要产品信息以及 6 列来存储数据(在此设置中,至少有三分之一为空)。添加的新属性意味着更改表以向其中添加另一列,并提出一个脚本来填充现有的,或者将所有现有的都保留为空。不是最好玩的,可能会让人头疼。
对此的替代方法是名称值对设置。您想要一个“标题”表来保存您的产品之间的共同值(例如名称或价格……所有产品始终具有的东西)。在上面的示例中,您会注意到每个记录都使用了属性“a”……这确实意味着属性 a 也可以是标题表的一部分。我们将这里的关键列称为“header_id”。
第二个表是一个参考表,它只是存储可以分配给每个产品的属性并为其分配一个 ID。我们将使用 atrr_id 作为键调用 table 属性。直截了当,上面的每个属性都是一行。
快速示例:
attr_id, attribute_name, notes
1,b, the length of time the product takes to install
2,c, spare part required
etc...
这只是您所有属性的列表以及该属性的含义。将来,您将在此表中添加一行,以便为每个标题打开一个新属性。
最终表是实际保存信息的映射表。您将获得产品 ID、属性 ID,然后是值。通常称为明细表:
prd1, b, 5 mins
prd1, c, needs spare jack
prd2, d, 'misc text'
prd3, b, 15 mins
查看数据如何存储为产品键、值标签、值?任何未来添加的产品都可以具有存储在此表中的任何属性的任意组合。添加新属性是在属性表中添加新行,然后根据需要填充详细信息表。
我相信也有一个 wiki...http://en.wikipedia.org/wiki/Entity-attribute-value_model
在此之后,它只是找出转出数据的最佳方法(我在这里推荐 Postgres 作为开源数据库选项)
【讨论】:
-1 票有什么意见吗?我认为这是一个很好的解释,为什么实体-属性模型最适合这种情况,因为需要快速添加新属性。附带说明...只要您不在 mysql(或 MS Access)上,此模型可很好地扩展,我在 postgres 环境中拥有数十亿行表,可以很好地处理此问题。 如果您想要任何级别的可扩展性,EAV 是一种反模式。对于简单的数据模型,它可能能够飞行,但在某种复杂程度下它就会崩溃。索引几乎是不可能的,并且查询可能会达到一定程度的复杂性,其中性能调整需要火箭科学家了解查询和数据库内部结构。您的数据模型和您跟踪的实体数量越复杂,EAV 的想法就越糟糕。 谢谢,我想我刚刚被称为火箭科学家。他的示例是具有 10 到 50 个属性的 5000 行...带有 MSAccess 的 486 可能可以处理它,我看不出这里会遇到问题的复杂程度。我并不是说您认为 EAV 模型最终会遇到扩展问题是错误的,但这个限制远远超出了他在这里的限制。您是否建议在这种情况下不要使用 oracle,因为它也有 128 TB 的表空间限制? 不,但是您对 EAV 和 Oracle 的局限性进行的比较是虚假的。 EAV 是一种已知的可扩展性反模式。它是有据可查的,当我在野外发现它时,它普遍是服务器上最重要的性能问题之一。 我不是在比较 EAV 和 Oracle 的局限性,而是在比较这种情况离这些局限性有多远。我们正在谈论的体积远低于解决可扩展性问题的 1%……如果您更喜欢比较,您会反对我用我的卡车移动一个 5 磅的箱子,因为它只能“扩大”到承载 5 吨?【参考方案3】:我不是 NoSQL 方面的专家,所以我不会提倡它。不过,我有几点可以帮助您解决有关关系数据库结构的问题。
我立即看到的第一件事是,您正在谈论继承(至少在概念上)。您的对象相互继承,因此您具有派生对象的附加属性。假设您正在添加一种新类型的对象,您需要做的第一件事(概念上)是为其找到一个基本/超级(父)对象类型,它具有属性的子集,并且您在它们之上添加(扩展基础对象类型)。
一旦您习惯了上述的思考方式,接下来就是关系数据库的继承映射模式。我将窃取 Martin Fowler 的术语来描述它。
您可以通过以下三种方式之一在数据库中保存继承链:
1 - 单表继承:整个继承链在一个表中。因此,所有新类型的对象都进入同一个表。
优点:您的搜索查询只有一个要搜索的表,并且它必须比例如连接更快。
缺点:例如,表的增长速度比选项 2 快;您必须添加一个 type
列,说明该行是什么类型的对象;有些行有空列,因为它们属于其他类型的对象。
2 - 具体表继承:为每种新类型的对象单独的表。
优点:如果搜索只影响一种类型,你一次只搜索一张表;例如,每个表的增长速度都比选项 1 慢。
缺点:如果同时搜索多个类型,则需要使用查询并集。
3 - 类表继承:基本类型对象的一个表仅具有其属性,附加表具有每个子对象类型的附加属性。因此,子表是指具有 PK/FK 关系的基表。
优点:所有类型都存在于一个表中,因此可以使用通用属性轻松搜索所有类型。
缺点:基表增长很快,因为它也包含部分子表;您需要使用 join 来搜索具有所有属性的所有类型的对象。
选择哪一个?
这显然是一种权衡。如果您希望添加多种类型的对象,我会选择提供合理查询和缩放选项的具体表继承。类表继承似乎对快速查询和可扩展性不太友好。单表继承似乎更适用于少量类型。
你的电话,我的朋友!
【讨论】:
以上是关于SQL 与 NoSQL 用于添加多个过滤器后将呈现给用户的数据的主要内容,如果未能解决你的问题,请参考以下文章