【问题标题】:Schema Migration Scripts in NoSQL DatabasesNoSQL 数据库中的架构迁移脚本
【发布时间】:2018-03-16 22:00:05
【问题描述】:

我有一个一直使用 C#、Entity Framework 和 SQL Server 的活动项目。然而,随着 NoSQL 替代方案的可行性日益增加,我正在研究将项目切换到使用 MongoDB 的所有影响。

很明显,主要的过渡障碍是由于“无模式”。 MongoDB 官方文档中的 here 很好地总结了 C# 等语言的含义。以下是最有用的相关段落(加粗):

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

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

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

或者,大多数关系数据库不支持,是 增量升级。这个想法是您的文档得到更新 因为它们被使用。从未使用过的文档永远不会更新。 正因为如此,你需要一些明确的陷阱 知道。

首先,查询一半文档是版本 1 的架构 一半的文档是版本 2 可能会出错。例如,如果 你重命名一个元素,那么你的查询将需要测试旧的 元素名称和新元素名称来获取所有结果。

其次,任何增量升级代码都必须保留在代码库中,直到 所有文件都已升级。例如,如果有 一个文档的 3 个版本,[1, 2, 3] 我们删除了升级代码 从版本 1 到版本 2,任何仍作为版本存在的文档 1 个不可升级。

SQL 生态系统中用于管理/创建此类初始化或升级脚本的工具非常成熟(例如Entity Framework Migrations

虽然在 NoSQL 世界 (though some believe there should not be) 中有可用于此类升级的 similar toolshomemade scripts,但似乎对于“何时”和“如何”运行这些升级脚本的共识较少。 Some 部署后建议。不幸的是,这种方法(当不与增量更新结合使用时)在尝试读取 C# 模型已更改的现有数据时会使应用程序处于不可用状态。

如果

The easiest strategy is to write an upgrade script.

对于像 C# 这样的静态 .NET 语言来说确实是最简单/推荐的方法,在 NoSql 数据库中是否有针对这些语言的代码优先模式迁移的现有工具?还是 NoSql 生态系统还没有成熟?

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

【问题讨论】:

  • NoSQL 数据库有很多种类型,你不能说成熟度和工具。 db-engines.com/en/ranking
  • 成熟度的重要来源可能是 SQL 之类的标准,但在 NoSQL 中几乎没有标准。即使存在像 SPARQL 这样的图形数据库,它也不会被一些流行的实现所尊重。恕我直言,对于行业和一些认为提供专有解决方案是好的而实际上并非如此的强大品牌来说,这是一种耻辱。
  • 即使脚本迁移的方法是最简单的方法,它也像是试图在 NoSQL 中模仿 SQL DB。更好的方法是接受 NoSQL 有很大的活力,它也应该影响编码风格和模式
  • @AndrzejMartyna 你能否给我一个更好的参考,说明如何处理这种 NoSQL “动态”应该影响 C# 中的编码风格和模式,而不是 I referenced from mongoDb's website?工具和文档的存在似乎比仅仅[您所指的 db-engines.com 网站中的“参考”方法](db-engines.com/en/ranking_definition.
  • 对这个问题缺乏兴趣,再加上网络上缺乏关于这个主题的信息,这让我相信没有可用的解决方案来让这些技术在我们的生产环境中运行,而无需大量投资滚动我们自己的解决方案来管理我们的 C# 模型更改时的架构更改。

标签: c# .net mongodb azure-cosmosdb entity-framework-migrations


【解决方案1】:

短版

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

没有。你可以做到这一点,但这不是 NoSQL 的强项。使用 C# 不会改变这一点。

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

我不知道。

还是说 NoSql 生态系统还没有成熟?

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

警告

首先,我很怀疑仅仅将现有的关系模型推送到 NoSql 会在一般情况下解决比它产生的问题更多的问题。

SQL 用于处理关系和数据集,noSQL 用于处理非关系数据:具有很少和/或软关系的“孤岛”。两者都擅长他们的目标,但他们擅长不同的事情。 它们不可互换。并非没有在数据重新设计、团队思维方式和应用程序逻辑变化方面做出认真的努力,这可能会使大多数以前的技术设计决策无效,并对架构系统属性和用户体验产生影响。

显然,这可能对您的情况有意义,但绝对在提交之前进行 ROI 数学运算

处理架构更改

假设您确实有充分的理由进行切换,并且模式更改管理是其中的关键,我建议不要与 NoSQL 的无模式特性抗争,而是接受它。接受您的数据将具有不同的架构。

不要做升级脚本

.. 除非您知道您的应用程序数据集永远不会显着增长或变化。 The other SO post you referenced 解释得很好。您只是不能依赖于能够长期做到这一点,因此无论如何您都需要一个 B 计划。不妨从它开始,并且仅在对于该特定情况确实是更简单的事情时才使用架构更新脚本。

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

同时支持多个模式

实际上预计会有不同的并发“活动”架构版本,因为无论如何都没有强制执行,这是您首先通过切换到 NoSQL 所购买的核心功能。

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

即使存储模型是无模式的,那么每个业务逻辑流程对输入模型(模式子集)都有期望,并且它应该验证它可以使用给定的内容。模型中的持久架构版本号也有助于处理更棘手的情况。

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

此外,如果输入模型不符合执行预期逻辑的要求,逻辑层应该有一个后备或反应计划,这一点很重要。取决于应用程序何时何地可以自动升级、接受丢弃、部分重置或必须定向到一些更棘手的修复队列(如果没有自动装置可以切断它,则需要手动修复)或必须完全拒绝请求,因为不兼容。

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

肯定需要权衡取舍。

那么,迁移?

一个缺点(如果您考虑迁移工具集的可用性)是您没有一个真正的架构来自动生成模型,或者它会发生变化,因为 C# 模型是真实架构的来源 您目前正在支持。实际上,这与代码优先的心态非常相似,但没有迁移。

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

结论

根据定义,NoSQL 不是 SQL。两者都很酷,但期待等效性或可互换性注定会遇到麻烦。

您仍然需要考虑和管理 NoSQL 中的模式,但如果您想要一个真正的强制和保证模式,那么请考虑使用 SQL。

【讨论】:

  • 感谢您的回答。您的“同时支持多个模式”中的信息是我正在寻找的解释。您能否在 C# 中使用这种方法的一些文档或示例中添加一些参考链接。
  • 我完全同意它解释 SQL 的方式的答案 - NoSQL 差异以及它如何影响开发工作
  • 毫无疑问!这是很好的信息。我只是觉得它缺少what makes for a great answer The answer can be “don’t do that”, but it should also include “try this instead”... Links to external resources are encouraged 的一部分,正如所写的那样,它没有说明我应该采取哪些下一步措施来理解问题域。我可以参考他建议如何使用 C# 和 NoSQL 的示例?
  • 我喜欢你遵循 SO 指导的方法,我也想学习它 - 看看我提出了什么巨大的答案 :( 也许问题太宽泛了,所以答案必须更具交叉性?我没有'没有找到任何好的引用来包含...
  • @jth41 不幸的是,我手头没有任何直接链接或参考资料,因为它基于各种尝试或收集的点点滴滴、个人品味,并且主要基于专有项目的工作。
【解决方案2】:

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

短版

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

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

免责声明

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

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

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

前线所在的地方

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

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

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

我的用例

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

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

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

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

接下来,图形数据库允许从不同的来源将任何东西“扔”到数据库中,并相互连接。简单地说,这个想法是让对象可以通过 ID 访问。

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

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

虽然解决方法真的很痛苦。

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

另一方面,发现和使用 Elastic Search 是一件非常愉快的事情!虽然很棒,但您必须意识到,在上传大量数据的压力下,它可能会崩溃,因此您必须调整工具以适应它

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

走向更广泛使用的方向

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

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

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

不同的方法

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

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

结论

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-09
    • 2014-12-09
    • 2010-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-04
    相关资源
    最近更新 更多