操作因素和数据模型


进入MongoDB中文手册(4.2版本)目录

为MongoDB建模应用程序数据时,应考虑影响MongoDB性能的各种操作因素。例如,不同的数据模型可以允许更有效的查询,增加插入和更新操作的吞吐量或更有效地将活动分配给分片群集。
开发数据模型时,请结合以下注意事项来分析应用程序的所有 读写操作

1 原子性

在MongoDB中,对单个文件写操作是原子性操作,即使操作修改多个嵌入式文档内的单个文件也是如此。当单个写入操作修改多个文档(例如db.collection.updateMany())时,对每个文档的修改都是原子的,但整个操作不是原子的。

1.1 嵌入式数据模型

嵌入式数据模型将所有相关数据合并到一个文档中,而不是跨多个文档和集合的规范化模型。该数据模型有助于原子操作。
有关为单个文档提供原子更新操作的数据模型的示例,请参见用于原子操作的模型数据

1.2 多文档事务

对于在相关数据之间存储引用的数据模型,应用程序必须发出单独的读取和写入操作并检索和修改这些相关数据。
对于需要对多个文档(在单个或多个集合中)进行读写原子性的情况,MongoDB支持多文档事务:

  • 在版本4.0中,MongoDB支持副本集上的多文档事务。
  • 在4.2版中,MongoDB引入了分布式事务,它增加了对分片群集上多文档事务的支持,并合并了对已有的副本集上多文档事务的支持。

有关MongoDB中事务的详细信息,请参阅事务页面。

重要
在大多数情况下,与单文档写入相比,多文档事务产生的性能成本更高,并且多文档事务的可用性不应代替有效的架构设计。在许多情况下, 非规范化数据模型(嵌入式文档和数组)对于您的数据和用例将继续是最佳的。也就是说,在许多情况下,对数据进行适当的建模将最大程度地减少对多文档交易的需求。
有关其他事务使用方面的注意事项(例如运行时限制和oplog大小限制),另请参见生产注意事项

2 分片

MongoDB使用分片提供水平扩展。这些集群支持具有大数据集和高吞吐量操作的部署。分片允许用户在数据库中对集合进行分区,并在多个mongod实例或分片中分布集合的文档。
为了在分片集合中分发数据和应用程序流量,MongoDB使用分片键。选择适当的分片键会对性能产生重大影响,并且可以启用或阻止查询隔离和写容量的增加。务必仔细考虑一个或多个字段用作分片键,这一点很重要。
分片分片键以获取更多信息。

3 索引

使用索引可以提高常见查询的性能。在查询中经常出现的字段以及返回排序结果的所有操作上建立索引。MongoDB在_id字段上自动创建唯一索引 。
创建索引时,请考虑以下索引行为:

  • 每个索引至少需要8 kB的数据空间。
  • 添加索引会对写操作产生一些负面的性能影响。对于具有高读写比的集合,索引会产生比较大的花销,因为每个插入也必须更新任何索引。
  • 具有较高读写比率的集合通常会受益于附加的索引。索引不影响未索引的读取操作。
  • 处于活动状态时,每个索引都会占用磁盘空间和内存。这种用法可能很重要,应该跟踪容量规划,尤其是对工作集大小有所担忧的时候。

有关索引以及分析查询性能的更多信息,请参见索引策略。此外,MongoDB数据库分析器可能有助于识别效率低下的查询。

4 大量的集合

在某些情况下,您可能选择将相关信息存储在多个集合中,而不是存储在单个集合中。
考虑一个样本集合logs,该样本用于存储各种环境和应用程序的日志文档。该logs集合包含以下格式的文件:

{ log: "dev", ts: ..., info: ... }
{ log: "debug", ts: ..., info: ...}

如果文档总数很少,则可以按类型将文档分组到集合中。对于日志来说,请考虑维护不同的日志集合,例如logs_dev和logs_debug。logs_dev 集合将仅包含与开发环境有关的文档。
通常,具有大量集合不会造成明显的性能损失,并且会导致非常好的性能。不同的集合对于高吞吐量批处理非常重要。
当使用具有大量集合的模型时,请考虑以下行为:

  • 每个集合都有一定的最小开销,只有几千字节。
  • 每个索引(包括_id上的索引)至少需要8kB的数据空间。
  • 对于每个数据库,一个命名空间文件(即 <database>.ns)存储该数据库的所有元数据,并且每个索引和集合在命名空间文件中都有其自己的条目(entry)。MongoDB对命名空间文件大小有限制。

5 包含大量小文档的集合

如果您有一个包含大量小文档的集合,则出于性能原因,应考虑嵌入。如果您可以按某种逻辑关系将这些小文档分组,并且经常通过此分组来检索文档,则可以考虑将这些小文档“汇总(rolling-up)”到包含嵌入式文档数组的较大文档中。
“汇总(rolling-up)”这些小文档到逻辑分组意味着,检索一组文档的查询涉及顺序读取和较少的随机磁盘访问。此外,“汇总(rolling-up)”文档以及将公共字段移动到较大的文档也有利于这些字段上的索引。这样会有公共的字段会有较少副本(copies)和也会减少相应索引相关联的键条目(key entries)。有关索引的更多信息,请参见 索引
但是,如果您通常只需要检索组中文档的一个子集,则“汇总”文档可能无法提供更好的性能。此外,如果小的独立的文档代表数据的自然模型,则应维护该模型。

6 存储优化小文档

每个MongoDB文档都包含一定量的开销。这种开销通常并不重要,但是如果所有文档都只有几个字节,那么这将变得很重要,如果您集合中的文档只有一个或两个字段,则可能会发生这种情况。
请考虑以下建议和策略,来优化这些集合的存储利用率:

  • 显式使用_id字段。
    MongoDB客户端会自动向每个文档添加一个_id字段,并为_id字段生成一个唯一的12字节的ObjectId。此外,MongoDB始终为该_id字段设置索引。对于较小的文档,这可能会占用大量空间。
    为了优化存储的使用,在将文档插入集合中时,用户可以为_id字段显式指定一个值。此策略允许应用程序在_id字段中存储一个值,该值本来会在文档的另一部分中占用空间。
    您可以在_id字段中存储任何值,但是由于此值用作集合中文档的主键,因此它必须唯一地标识它们。如果该字段的值不是唯一的,则它不能用作主键,因为在集合中会发生冲突。

  • 使用较短的字段名称

    注意
    缩短字段名称会降低表达能力,并且对于较大的文档以及文档开销不太重要的情况,不会带来很大的好处。较短的字段名称不会减少索引的大小,因为索引具有预定义的结构。
    通常,没有必要使用短字段名。

    MongoDB在每个文档中存储所有字段名称。对于大多数文档,这只占文档使用空间的一小部分;但是,对于小型文档,字段名称可能会按比例占用大量的空间。考虑类似于以下内容的小文件的集合:

    { last_name : "Smith", best_score: 3.9 }
    

    如果将last_name缩短名为lname并命名地best_score为score,如下所示,你可以保存每个文档9个字节。

    { lname : "Smith", score : 3.9 }
    
  • 嵌入文件
    在某些情况下,您可能希望将文档嵌入其他文档中,并节省每个文档的开销。请参阅包含大量小文档的集合。

7 数据生命周期管理

数据建模决策应考虑数据生命周期管理。
在集合的生存时间或TTL特性使文档在一段时间后过期。如果您的应用程序需要一些数据在有限的时间内保留在数据库中,请考虑使用TTL特性。
此外,如果您的应用程序仅使用最近插入的文档,请考虑固定集合。固定集合提供对插入文件的先入先出(FIFO)的管理,并基于插入顺序有效地支持插入和读取文件操作。

进入MongoDB中文手册(4.2版本)目录

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值