如何从完整的SQL查询转向类似NoSQL的东西?

3
在我的一个进程中,我有一个SQL查询占用了总执行时间的10-20%。这个SQL查询在我的数据库上进行过滤,并加载一系列的PricingGrid对象。所以我想要提高这些性能。到目前为止,我猜测有两种解决方案:
1.使用NoSQL解决方案,据我所知,这些是改善读取过程的好方案。
但是迁移似乎很困难,需要大量的工作(例如定期从SQL Server导入数据到NoSQL中)。
我没有任何知识,甚至不知道应该使用哪个(我会使用Ravendb,因为我关注ayende,它是由.net社区完成的)。
我可能需要更改我的模型,使我的对象适用于NoSQL数据库。
2.将所有PricingGrid对象加载到内存中(在静态IEnumerable中)。
当我的服务器没有足够的内存来加载所有内容时,这可能会成为问题。
我可能会重新发明NoSQL提供程序发明的轮子(索引等)。
我认为我不是第一个想知道这个问题的人,那么最好的解决方案是什么?是否有任何工具可以帮助我?
.NET 3.5,SQL Server 2005,Windows Server 2005。

4
还有可能提高您的查询速度。您能否详细说明您正在运行的查询类型,正在查询的表格大小和结果数量,以及正在使用的索引? - DNA
查询主要涉及5个表,我使用执行计划创建了一些索引(无需扫描表),PricingGrid表(主表)有60k条记录(选定的有14k行),输出结果包括5个表。发布我的SQL查询细节会完全改变我的问题目的。 - remi bourgarel
1
@remi:你提出问题的目的是“所以我想要提高这些性能。” DNA正确指出,最简单的方法可能是更好地使用您已经存在的SQL Server和SQL设计。我可以向您保证,除非您计划在半打服务器上分发查询,否则NoSQL对于您的性能没有任何实质性的帮助,您不能从SQL Server中获得。特别是对于一个5个表的查询,在NoSQL解决方案上可能比在SQL上慢。 - RBarryYoung
@RBarryYoung,我有六个服务器,只是好奇如何从一种解决方案迁移到另一种,以评估哪种最快实施。这个查询已经存在4年了,我已经多次发布问题以优化它(并且成功了)。这就是为什么我在考虑其他解决方案而不是第1000次阅读我的执行计划并最终赢得1ms。 - remi bourgarel
2个回答

3
从 SQL 迁移数据只是第一步。迁移到文档存储(如 RavenDB 或 MongoDB)也意味着您需要:
  • 去规范化您的数据
  • 在代码中执行架构验证
  • 处理复杂操作的并发性,因为您不再拥有事务(至少不是同样的方式)
  • 在部分提交(更改)的情况下执行回滚
  • 根据您的更新、读取和网络模型,您可能还需要处理冲突

您提供的信息非常有限,但听起来您的需求包括单个数据库服务器,并且您的数据在关系模型中很好地适配。

在这种情况下,我会反对使用 NoSQL 解决方案,更有可能通过数据库优化加快查询速度,同时保留所有关系型数据库管理系统的附加价值。

非关系型数据库是一种特定工作的工具(无论它们如何销售),如果您需要使用它们,通常是因为您的数据不适合关系模型,或者您需要将数据分布在多台机器上(大小或可用性)。例如,我使用MongoDB来处理写入密集型高吞吐量的作业管理应用程序。它是集中式的,数据非常短暂,因此具有低耐久性的“成本”是可以接受的。这听起来对您来说似乎不是这种情况。
如果您更喜欢使用NoSQL解决方案,也许您应该尝试使用Memcached+MySQL(InnoDB),这将允许您获得内存缓存的速度优势(以memcached守护进程插件的形式),并具备RDBMS(MySQL)的底层保护和功能。它还应该简化数据迁移,并在一定程度上减少您的代码所需的更改量。我自己从未使用过它,我发现我要么因为我上面所述的原因需要NoSQL,要么我可以使用存储过程、索引和表视图来优化RDBMS,以满足我的需求。

我这里不只有一台服务器,而是五台:一台主服务器接收所有写入查询,另外四台从服务器用于查询。我们的数据很适合关系模型,因为我们是这样设计的,当时没有其他选择。这里不需要报告,写入查询可能只占这些数据查询的1%。我会看看memcache或任何微软的替代方案... - remi bourgarel
听起来缓存是正确的选择。在1%的写入和主从配置下,选择NoSQL更多地取决于你有多少数据以及你想要实现什么样的可用性。顺便说一句,提前考虑如何表示您的数据是一件好事,当您无法以任何有意义的方式结构化您的数据时,文档存储通常是正确的选择。例如,将JSON对象存储在CLOB中。 - Asaf
在这里,缓存并不是很容易或高效的:如果我缓存所有数据,仍然需要过滤它们(这是最耗费的部分,数据量并不是很大)。如果我缓存所有不同的请求,我永远不会读取缓存,因为每个请求都是不同的(其中一些是关于10个产品的,有些是关于10,000个产品的,有些来自不同的来源,还有日期组件,所以有无限的可能性)。 - remi bourgarel

2
Asaf提供了关于使用NoSQL及何时使用的重要信息。考虑到您的主要问题是性能,我倾向于同意他的观点——采用一个全新(且非常不同)的数据持久化平台需要更多的时间和精力,相比之下,优化SQL Server集群会更简单。话虽如此,我的回答主要是针对您问题中“如何”的部分。

纠正误解:

数据去规范化 - 在迁移现有数据时,您无需手动进行数据去规范化。这将在迁移过程中为您完成。最重要的是,您需要以不同的方式思考您的数据- 根聚合、实体和值类型等。
并发/事务 - Mongo和Raven都支持事务,只是使用不同的方式。 Raven之所以能够实现这一点,是通过使用类似ORM的“工作单元”模式来处理其RavenSession对象。是的,您的数据验证需要在代码中完成,但您应该已经在那里完成了。在我的经验中,这是一个被夸大的缺点。
在主服务器上安装Raven或Mongo,并将其作为服务运行。 创建或扩展现有应用程序,使用您打算迁移的数据库。此应用程序需要所有模型类/库,以使您的SQL数据库提供持久性。 a. 在“数据层”中,您可能已经有了一个存储库类。从中提取一个接口,并使用它构建另一个用于Raven/Mongo持久性的存储库类。这两个数据库都有很好的文档,可以使用它们的API来推送/拉取/更新文档图中的更改。这非常简单。 b. 将SQL数据加载到C#对象中。在内存中获取顶级对象(仅实体),并加载其内部集合和相关数据。您的存储库可能已经在执行此操作(例如,在获取Order对象时,请确保不仅加载其属性,而且还加载了关联集合,如Items)。 c. 实例化您的Raven/Mongo存储库并将数据推送到其中。主要实体成为序列化为JSON的“顶级文档”或“根聚合”,其集合数据嵌套在其中。保存更改并关闭存储库。注意:您可以根据数据的需要将此步骤拆分为许多小块。 数据迁移完成后,请对其进行测试并确保满意。您可能需要稍微修改应用程序模型,以调整它们被持久化到Raven/Mongo的方式 - 例如,您可能希望将OrdersItems都作为顶级文档,并简单地使用引用值(类似于关系型数据库系统中的关系)。但是请注意,在这里进行操作有点违反NoSQL背后的原则和性能,因为现在您必须两次访问数据库才能获取订单和项目。 如果满意,请跨您剩余的可用服务器盒子分片/复制您的mongo/raven服务器。
显然,我没有解释很多小细节,但这是一般的过程,很大程度上取决于已经使用数据库的应用程序,并且如果超过一个应用程序/系统与其通信,则可能会很棘手。

最后,再次重申Asaf所说的...尽可能多地了解NoSQL及其最佳用例。它是一个惊人的工具,但不是所有数据持久性的黄金解决方案。在您的情况下,请尝试真正找到当前解决方案中的瓶颈,并查看它们是否可以解决。正如我的系统管理员之一所说,“为了技术而技术是胡说八道”。


我完全同意你的同事,这就是为什么我提出这个问题,想了解一下这项新技术,并看看所提供的解决方案在性能和开发时间方面是否高效。我真的很喜欢你的回答,因为你走了这条路线。 - remi bourgarel
@remibourgarel 非常好。说真的,记得选择适合工作的正确工具。快速启动一个Raven的单服务器实例(如果你有一个.Net应用程序,比Mongo更好的工具),并尝试一下。编写一个小型控制台应用程序,从数据库中提取集合并将其填充到Raven中...测量你花费的时间以及如何在大规模上完成它。如果值得你的时间,那太好了,否则,请参考Tekpub或Pluralsight的SQL性能教程和书籍,或者在这里查看所有文章。祝你好运。 - one.beat.consumer
说得非常好,@one.beat.consumer。我要强调的是,在我的看法中,在您的数据上执行“JOIN”有点违背使用类似MongoDB这样的东西的初衷。但是,再次强调,如果不知道确切的用例,我就不能做出任何概括。 - Asaf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接