IBM Cloud Docs
数据建模

数据建模

数据建模文档是该系列中的第一个最佳实践文档。 它向您显示以下最佳实践:

  • 您需要了解的有关 API 的信息。
  • 如何对数据进行建模。
  • 必须使用的文档大小。
  • 要避免的内容。
  • 如何配置数据库。

有关更多信息,请参阅 建立索引和查询IBM Cloudant 实践

本文档中的内容最初由 Stefan Kruger 在 2019 年 11 月 21 日作为 最佳和最差实践 博客帖子编写。

了解要作为目标的 API

您可以使用 Java™PythonGoNode.js 或其他特定于用例的语言或平台。 其中一种语言很可能随附方便的客户端库,这些库可按照您期望的工具约定,很好地集成 IBM Cloudant 访问。 这些语言对于程序员效率非常好,但它们也隐藏了 API 的视图。

这个抽象是你想要的,使用客户端库的全部原因是为了拯救自己重复的,乏味的锅炉电镀。 但是,在对问题进行故障诊断和报告时,您必须了解底层 API 至关重要。 当您向 IBM Cloudant报告可疑问题时,如果您可以为我们提供重现问题的方法,那么它将帮助我们提供帮助。

此请求并不意味着将应用程序的大量 Java™ 源逐字地剪切并粘贴到支持凭单中,因为我们可能无法构建该支持凭单。 此外,您的客户端代码还会带来不确定因素,即问题可能出在何处,您的一方或我们的一方?

相反, IBM Cloudant的支持团队通常会请求一组 API 调用 (理想情况下作为他们可以运行的一组 curl 命令) 来演示此问题。 通过采用此方法作为规则进行故障诊断,您还可以更轻松地确定问题的故障位置。 如果您的代码行为异常,请尝试仅使用对 API 的直接访问来重现问题。

如果不能,那么问题不在于 IBM Cloudant 服务本身。

如果您正在调查性能问题,请参阅 IBM Cloud®提供的日志。 如果日志显示请求由 IBM Cloudant快速处理,但应用程序速度缓慢,那么该问题的根源在于客户机端应用程序代码。 请参阅有关 日志记录和监视的规则。

如果您怀疑官方支持的客户机库存在问题,请尝试构造一个演示该问题的小型自包含代码示例。 在此自包含代码示例中,使用尽可能少的其他依赖关系。 如果您正在使用 Java™,那么如果您可以使用最少的 测试装置 来突出显示库问题,那么这对我们很有帮助。

有时, IBM Cloudant 会收到支持凭单,表明 "IBM Cloudant 已损坏,因为我的应用程序很慢" ,而没有大量支持证据。 几乎始终可以将此案例追溯到客户端上的应用程序代码中的问题,或者对 IBM Cloudant 工作方式的误解。

并不总是,但几乎总是。

通过更好地了解 API ,您还可以获得有关 IBM Cloudant 行为方式的经验,尤其是在性能方面。 如果您正在使用客户机库,那么必须至少了解如何确定特定函数调用所生成的 HTTP 请求。 有关更多信息,请参阅以下 Web 站点:

文档必须将大部分更改的数据分组在一起

当您开始对数据进行建模时,您迟早会迂到如何构造文档的问题。 现在,您知道 IBM Cloudant 不会强制实施任何规范化,并且它没有您习惯使用的类型的事务,例如 Postgres。 诱惑可以是尽可能多地补习到每个文档中,这也会节省 HTTP 使用。

这种做法往往是一个不好的想法。

如果模型将未一起更改的信息分组在一起,那么您更有可能遭受更新冲突的影响。

请考虑您有用户的情况,每个用户都有一组与其关联的订单。 一种方法可能是将订单表示为用户文档中的数组:

{ // DON'T DO THIS
    "customer_id": 65522389,
    "orders": [ {
      "order_id": 887865,
      "items": [ {
          "item_id": 9982,
          "item_name": "Iron sprocket",
          "cost": 53.0
        }, {
          "item_id": 2932,
          "item_name": "Rubber wedge",
          "cost": 3.0
        }
      ]
    }
  ]
}

要添加订单,我需要访存完整文档,取消编组 JSON ,添加项,编组新 JSON ,并将其作为更新发送回。 如果我是唯一这样做的人,可能会工作一段时间。 如果文档正在并发更新或复制,那么我们可能会看到更新冲突。

而是将订单作为自己的文档类型进行分隔,并引用客户标识。 现在模型是不可改变的。 要添加订单,请在数据库中创建新的订单文档,这不会生成冲突。

为了能够检索特定客户的所有订单,我们可以采用一个视图,我们稍后将覆盖此视图。

避免使用依赖于现有文档部分更新的构造 (如果可能)。 糟糕的数据模型通常在您投入生产后难以改变。

可以使用分区数据库对先前的模式进行高效求解,稍后将更详细地介绍这些数据库。

有关更多信息,请参阅以下文档:

保持文档较小

IBM Cloudant 施加最大文档大小 1 MB。 此限制并不意味着 close-to-1-MB 文档大小是一个好主意。 相反,如果您发现正在创建超过个位数 KB 的文档,那么可能需要重新访问您的模型。 随着文档的增长, IBM Cloudant 中的一些内容的性能会降低。 例如, JSON 解码成本高昂。

让我们查看以下部分: 文档必须将大部分更改的数据分组在一起保持文档小。 值得强调的是,依赖于更新的模型的最大容量限制为 1 MB ,即文档大小的截止值。 这个大小不是你想要的。

避免使用附件

IBM Cloudant 支持将附件与文档一起存储,这是它从 CouchDB继承的一项长期功能。 如果使用 IBM Cloudant 作为 Web 应用程序的后端,那么还可以将小图标和其他静态资产 (例如 CSS 和 JavaScript 文件) 与数据一起存储。

在今天使用 IBM Cloudant 中的附件之前,必须考虑一些事项,尤其是如果您正在查看更大的资产 (例如图像和视频):

  1. IBM Cloudant 贵为块存储器。
  2. IBM Cloudant的内部实现无法高效处理大量二进制数据。

所以,慢而贵。

对于小型资产和偶尔使用,可以接受 IBM Cloudant 。 通常,如果需要将二进制数据与 IBM Cloudant 文档一起存储,那么最好使用更适合此目的的单独解决方案。 您只需要将附件 元数据 存储在 IBM Cloudant 文档中。 是的,这意味着您需要编写一些额外的代码,以将附件上载到您选择的合适块存储器。 在将令牌或 URL 存储到 IBM Cloudant 文档中的附件之前,请验证是否成功。

您的数据库更小,更便宜,更快,更易于复制。 有关更多信息,请参阅以下 Web 站点:

更少的数据库比更多的数据库更好

如果可以,请将每个 IBM Cloudant 帐户的数据库数限制为 500 或更少。 虽然此特定数字并非魔法 (IBM Cloudant 可以安全地处理更多) ,但存在多个受帐户中大量数据库负面影响的用例。

复制器调度程序具有其准备运行的有限数量的同时复制作业。 随着数据库数量的增加,如果尝试复制帐户中包含的所有内容,那么复制等待时间可能会增加。

同一枚硬币的另一面是操作方面: IBM Cloudant的操作团队也依赖于复制来移动帐户。 通过减少数据库数量,您可以帮助我们在需要将帐户从一个位置转移到另一个位置时提供帮助。

那么什么时候必须使用单个数据库,通过使用视图来区分不同的文档类型,什么时候必须使用多个数据库来对数据进行建模? IBM Cloudant 无法跨多个数据库联合视图。 如果您具有从不 "连接" 或一起查询的不相关数据,那么该数据可以是跨多个数据库拆分的候选数据。

如果您拥有不断增长的数据集 (如日志,传感器读数或其他类型的时间序列) ,那么创建单个不断增长的海量数据库也不是一个好主意。 此类用例需要时间装箱,稍后我们将更详细地介绍这些用例。

避免 每个用户的数据库 像瘟疫一样反模式

如果要在 IBM Cloudant上构建多用户服务,那么允许每个用户将其数据存储在应用程序帐户下的单独数据库中很有吸引力。 这很管用,大部分情况下,如果用户数量少的话。

现在,添加了派生跨用户分析的需求。 执行此操作的方法是将所有用户数据库复制到单个分析数据库中。 一切都好 这个应用突然变得成功了,用户数量增长在 150-20,000 人的范围内。 您有 20,000 个复制,只是为了使分析数据库保持最新。 如果您还希望在主动/主动灾难恢复设置中运行,请再添加 20,000 个复制,然后系统停止运行。

而是将用户数据多路复用到较少的数据库中,或将用户分片到一组数据库和/或帐户中。 这样,您无需复制即可提供分析数据库,但认证变得更加复杂,因为 IBM Cloudant 仅提供数据库级别的认证。

值得指出的是, "database-per-user" 方法很诱人,因为 IBM Cloudant 许可权是 "每个数据库" ,但出现此模式并不是真正的用户故障。

避免编写定制 JavaScript reduce 函数

IBM Cloudant 中的 MapReduce 视图很棒。 然而,有了巨大的力量,就有了巨大的责任。 MapReduce 视图的映射部分以递增方式构建,因此映射中的伪劣代码仅影响索引时间,而不会影响查询时间。 不幸的是, reduce-part 在查询时运行。 IBM Cloudant 提供了一组在 Erlang中内部实现的内置 reduce 函数。 这些函数可大规模执行,而您亲手制作的 JavaScript 不会减少。

如果您发现自己编写了 reduce 函数,请停止并考虑是否可以重组数据,以便不需要编写 reduce 函数。 或者让你能够依赖内置的还原器。

分区数据库上的视图不支持定制缩减,这是仅此类视图可提供的显着加速查询的一个因素。

有关更多信息,请参阅 上的 IBM Cloudant 文档

将时间框数据库用于不断增长的数据集

在 IBM Cloudant中拥有一个不断增长的数据库通常 不是 好主意。 大型数据库可能难以备份,需要 "重新扫描" 以保持其增长时的良好性能,并遭受长时间索引构建时间的影响。

缓解此问题的一种方法是改为具有多个较小的数据库,其公共模式为 time-boxed databases: 将大型数据集拆分为较小的数据库,每个数据库表示一个时间窗口,例如,一个月。

  • orders_2019_01
  • orders_2019_02
  • orders_2019_02

新数据将写入本月的数据库,历史数据的查询可定向到前几个月的数据库。 当不再关注某个月的数据时,可以将其归档到 Object Storage,删除每月 IBM Cloudant 数据库,并恢复磁盘空间。 有关更多信息,请参阅以下 Web 站点。