NoSQL数据库中的模式迁移脚本

jth*_*h41 9 .net c# mongodb ef-migrations azure-cosmosdb

我有一个活动项目,一直使用C#,实体框架和SQL Server.但是,随着NoSQL备选方案日益增加的可行性,我正在研究将项目转换为使用MongoDB的所有影响.

很明显,主要的过渡障碍是由于"无架构".什么暗示对于像C#语言的一个很好的总结发现这里的官方MongoDB的文档.以下是最有用的相关段落(粗体添加):

仅仅因为MongoDB是无模式的并不意味着您的代码可以处理无模式文档.最有可能的是,如果您使用的是静态类型语言(如C#或VB.NET),那么您的代码就不灵活,需要映射到已知的模式.

架构可以通过多种不同方式从应用程序的一个版本更改为下一个版本.

你如何处理这些取决于你自己.有两种不同的策略:编写升级脚本.在使用文档时逐步更新文档.最简单的策略是编写升级脚本.关系数据库(SQL Server,Oracle)和MongoDB之间的这种方法实际上没有区别.确定需要更改的文档并进行更新.

或者,在大多数关系数据库中不支持,是增量升级.我们的想法是,您的文档在使用时会得到更新.从未使用的文档永远不会更新.因此,您需要注意一些明确的陷阱.

首先,针对一半文档是版本1而一半文档是版本2的架构的查询可能会出错.例如,如果重命名元素,则查询将需要测试旧元素名称和新元素名称以获取所有结果.

其次,任何增量升级代码必须保留在代码库中,直到所有文档都已升级.例如,如果有文档的3个版本,[1,2和3]并且我们将升级代码从版本1移除到版本2,那么仍然作为版本1存在的任何文档都是不可升级的.

用于在SQL生态系统中管理/创建此类初始化或升级脚本的工具非常成熟(例如,实体框架迁移)

虽然在NoSQL世界中有类似的工具自制脚本可用于此类升级(尽管有些人认为不应该这样),但似乎对"何时"和"如何"运行这些升级脚本的共识较少.有些建议在部署之后.不幸的是,这种方法(当不与增量更新一起使用时)可能会在尝试读取C#模型已更改的现有数据时使应用程序处于不可用状态.

如果

" 最简单的策略是编写升级脚本. "

对于像C#这样的静态.NET语言来说,它是真正最简单/推荐的方法,是否存在用于这些语言的NoSql数据库中代码优先模式迁移的现有工具?或NoSql生态系统没有到那个成熟点?

如果您不同意MongoDB的建议,那么什么是更好的实现,您能否提供一些参考/示例,说明我在哪里可以看到正在使用的实现?

Imr*_*vel 7

简洁版本

是“最简单的策略是编写升级脚本”。对于像C#这样的静态.NET语言,真的是最简单/推荐的方法吗?

不。您可以这样做,但这不是NoSQL的优势。使用C#不会改变这一点。

NoSql数据库中针对这些语言的代码优先模式迁移是否有现有工具?

不是我知道的。

还是NoSql生态系统还不成熟?

它是无模式的。我认为这不是目标或成熟度。

警告事项

首先,我很怀疑只是将现有的关系模型推送到NoSql会解决比创建的问题更多的问题。

SQL用于处理关系和数据集,而noSQL则用于处理非关系数据:具有很少和/或软关系的“孤岛”。两者都擅长于所针对的目标,但它们擅长于不同的事情。它们不可互换。在数据重新设计,团队思维定势和应用程序逻辑更改上不花大力气,可能会使大多数以前的技术设计决策无效,并且影响力最终取决于体系结构系统属性,甚至可能取决于用户体验。

显然,这对您来说很有意义,但一定要在提交之前进行ROI数学运算

处理架构变更

假设您确实有充分的理由进行切换,而模式变更管理是其中的关键,那么我建议您不要与NoSQL的无模式本质抗争,而应该拥抱它。接受您的数据将具有不同的架构。

不要升级脚本

..除非您知道应用程序数据集永远不会显着增长或更改。您引用的另一篇SO帖子对此进行了很好的解释。您只是不能长期依赖此功能,因此无论如何您都需要一个计划B。最好从它开始,并且如果确实是针对该特定情况进行的更简单的操作,则仅使用架构更新脚本。

我也许会补充说,一个好的NoSQL优化数据模型通常针对单项查找和写入进行了优化,而批量更新比SQL可能要重得多,即,更新单个字段可能需要重写更大的字段。本文档的+部分可能会处理一些引入的非规范化,以减少在noSQL中进行查找的需求(甚至可能不是事务性的)。因此,在衡量升级停机时间时,NoSql中的“大”可能恰好比您预期的要小得多且发生得更快。

同时支持多种架构

实际上,由于没有强制执行,因此实际上期望具有不同的并发“活动”模式版本,这是您首先通过切换到NoSQL所要购买的核心功能。

理想地,以noSQL的心态,您的逻辑应该能够处理满足特定过程要求的任何输入数据。它应该取决于其所需的输入,而不取决于您的存储模型(对于依赖管理以降低复杂性,这也具有普遍意义)。也许逻辑仅取决于单一文档类型中的一些属性。只要其他字段已更改或添加了一些额外的数据(只要它们与要完成的给定工作无关),它就不会中断。绝对不应该在乎其他模型类型是否已更改。这种方法通常意味着要处理一些软值包(JSON /动态/字典/等)。

即使存储模型是无模式的,每个业务逻辑流程也对输入模型(模式子集)抱有期望,并且应该验证输入模型是否可以使用给定的模型。沿模型保留的模式版本号在棘手的情况下也有帮助。

作为C#的人,我个人避免直接使用动态模型,而更喜欢创建一个强类型的对象来包装每种动态存储类型。为了避免管理N个并发模式版本模型(差异最小)并不断升级逻辑层以支持新的模式版本,我将其实现为给定实体的所有当前支持的模式版本的超集,并实现所需的任何接口。当然,您可以添加N个以上的抽象层;)一旦一些旧的架构版本最终从数据中淘汰,您可以简化模型并获得强类型支持以覆盖所有依赖项。

同样,重要的是,如果输入模型不符合执行预期逻辑的要求,则逻辑层应具有备用或反应计划。这取决于应用程序的时间和位置,您可以在何时何地自动升级,接受丢弃,部分重置或必须定向到一些棘手的维修队列(如果没有自动切割机,则可以手动修复)或必须完全拒绝该请求,因为不兼容。

是的,存在跨不同版本的模型集进行查询的问题,因此您也应该始终考虑这些情况。您可能需要调整查询逻辑以分别查询不同的版本并合并结果(或接受部分结果,如果可以接受的话)。

当然,肯定有折衷考虑。

那么,迁移呢?

不利的一面(如果考虑迁移工具集的可用性)是因为您没有一个真正的架构来自动生成模型,或者由于C#模型是您当前支持的事实来源架构,所以它会发生更改。实际上,这与代码优先的思维方式非常相似,但是没有迁移。

您可以实现一个传入模型管道,该管道将在读取模型时自动升级模型,从而减少您需要在上游支持的架构版本的数量。我会说,这与您所获得的迁移非常接近。我不知道有任何工具可以自动为您执行此操作,并且不确定是否会这样做。需要权衡取舍,例如,某些使用数据的客户端可能会在不同的时间轴上进行升级等。升级到最新版本可能并非总是您想要的。

结论

根据定义,NoSQL不是SQL。两者都很酷,但是期望等效性或可互换性必然会带来麻烦。

您仍然必须考虑和管理NoSQL中的架构,但是如果您想要一个真正的强制和保证架构,请考虑使用SQL。

  • 毫无疑问!这是很好的信息。我只是觉得它缺少[什么是一个很好的答案](https://stackoverflow.com/help/how-to-answer)`答案可以是“不要那样做”,但它也应该包括“试试这个”......鼓励链接到外部资源`正如所写,它没有提供我应该采取什么下一步来理解问题域的指示。我可以参考什么作为他建议使用 C# 和 NoSQL 的示例? (3认同)

And*_*yna 5

虽然伊姆雷的回答确实很棒,而且我在每个细节上都同意它,但我想添加更多内容,但也尽量不重复信息。

简洁版本

如果您打算将现有的 C#/EF/SQL 项目迁移到 MongoDB,那么您很可能不应该这样做。它可能运行得很好一段时间,团队知道这一点,并且可能已经修复了数百个或更多的错误,用户或多或少对此感到满意。这就是你已经拥有的真正价值。我是认真的。有关不应使用新代码替换旧代码的原因,请参阅此处:https: //www.joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i/

对于任何技术来说,比工具的存在更重要的是它带来的价值并且它按承诺工作(工具是次要的)。

免责声明

  1. 我不喜欢您引用的 mongoDB 的解释,该解释声称静态类型语言是这里的一个问题。这是真的,但只是在基本的、表面的层面上。稍后会详细介绍这一点。

  2. 我不同意 EF Code First 迁移已经非常成熟 - 尽管它非常适合开发和测试环境,并且比以前的 .NET 数据库优先方法要好得多,但您仍然必须有自己谨慎的生产方法部署。

  3. 投资自己的工具不应该成为您的障碍。事实上,如果您选择的引擎真的很棒,那么围绕它编写一些特定的工具是值得的。我相信伟大的团队很少使用“现成的”工具。他们宁愿明智地选择技术,然后根据自己的需求定制工具或围绕它构建新工具(可能在一两年后出售该工具)。

前线所在的地方

它不在静态类型语言和动态类型语言之间。这种差异被严重高估了。它更多地涉及手头的问题和模式的性质。模式的一部分是相当静态的,它在静态和动态“世界”中都能很好地发挥作用,但其他部分可以随着时间自然变化,它更适合动态类型语言,但不适合动态类型语言。

您可以轻松地在 C# 中编写具有对(键、值)列表的代码,从而控制动态性。动态类型语言给您的印象是您直接调用属性,而在 C# 中您通过“key”访问它。虽然对于开发人员来说使用起来更简单、更漂亮,但它并不能帮助您避免更大的问题,例如部署架构更改、访问不同版本的架构等。

所以静态/动态语言的情况在这里根本不是问题。相反,它是在您想要从代码中控制的数据(涉及任何逻辑)和您不必严格控制的其他部分之间划出一条线。第二部分不必在代码中的模式中明确而详细地表达(它可以是列表或字典,而不是命名字段/属性,因为维护这些字段会花费您但不会带来任何价值)。

我的用例

曾几何时,我的团队做了一个使用三个不同数据库的项目:

  1. 用于“常用”配置和证据的 SQL
  2. 图形数据库使构建任意连接对象的广泛网络变得自然
  3. 为搜索而调整的文档数据库(实际上是 Elastic Search),使搜索变得即时且真正现代化(例如处理拼写错误等)

当然,部署如此广泛的技术堆栈是一个挑战,但它的每个部分都为整个解决方案带来了最好的效果。该项目的目的是搜索几乎任何内容(项目、人员、书籍、产品、文档,任何东西)的知识库。

这就是为什么 SQL 在这里只是记录可用“知识数据库”的列表以及分配给它们的用户。这里的模式是明显的、稳定的和琐碎的。未来发生变化的可能性很小。

接下来,图形数据库允许将任何来自不同来源的任何内容“扔”到数据库中,并将事物相互连接起来。简而言之,这个想法是让对象可以通过 ID 访问。

接下来,弹性搜索将积累 ID 和选定的属性子集,以便立即搜索它们。这里的模式仅包含 ID 和对(键、值)的列表。

作为最后一步,简单地说,该解决方案调用 Elastic Search,获取 Id 并显示详细信息(模式是无关紧要的,因为我们将其视为键 x 值对的列表,因此 GUI 准备动态构建屏幕)。

尽管解决问题的过程确实很痛苦。

我们通过运行概念证明测试了一些图数据库,发现它们中的大多数根本无法用于更新数据等操作!(呃!!!)我们终于找到了一个足够好的数据库。

另一方面,查找和使用 Elastic Search 是一种极大的乐趣!尽管很出色,但您必须意识到,在上传大量数据的压力下,它可能会崩溃,因此您必须调整工具以适应它

(所以这里没有灵丹妙药)。

走向更广泛应用的方向

除了我的用例有点极端之外,通常你会有“中间”的东西。

例如文档数据库。它可以具有几乎静态的字段“标题”,例如 ID、名称、作者等,并且您的代码可以“传统”地管理它,但所有其他字段都可以以其存在或不存在并且可以具有不同内容的方式进行管理或结构。

“标题”是您决定使其与项目相关并可由项目控制的部分。其余的都是伴随性的而不是关键性的(从项目逻辑的角度来看)。

不同的方法

我宁愿建议了解特定 NoSQL 数据库类型的优势,找到创建它们的原因、它们为什么流行和有用的答案。然后回答他们可以通过哪些方式为您的项目带来收益。 顺便提一句。这很有趣,为什么你提到 MongoDB?

另一种方法是从技术角度回答您的项目当前最大的弱点或最大的挑战是什么 - 性能、支持成本变化、需要大幅扩展或其他。然后尝试回答某些 NoSQL DB 是否可以很好地解决该问题。

结论

我相信您可以通过替换部分数据库或为用户带来新的价值(例如搜索?)来发现 NoSQL 数据库对您的项目的好处。不管怎样,我更喜欢一种真正优秀的技术,能够带来它所承诺的东西,而不是看看它是否得到周围工具的完全支持。

而且概念证明是一个非常好的工具,可以在非常简单但同时对您有意义的场景中检查技术。但方法不应该是玩弄技术,而应该积极、快速地证明或反驳技术的质量。

周围有太多的承诺和广告,我们应该通过关注真正有效的事情来保护自己。