关于时间序列数据
在内部, MongoDB根据常见的 metaField
值对时间序列集合中的文档进行分组,从而优化时间序列数据。选择一个有用的可显着优化存储密度和查询性能。有关更多信息,请参阅元字段。
时间序列数据的属性
时间序列数据具有几个有别于其他数据格式的属性:
文档按顺序到达,需要频繁的插入操作来追加文档。
更新操作很少见,因为每个文档都代表一个时间点。
如果您的应用程序受益于大量的历史记录,则很少会执行删除操作。
数据按时间和标识符(例如股票报价器)进行索引,该标识符可标识数据所属的唯一时间序列。
数据量很大,因为每个单独的时间序列都需要大量且不断增长的文档。
考虑到这些因素, MongoDB使用专门的柱状格式将每个时间序列的文档分组在一起。这样做有以下好处:
减少存储和索引大小
提高查询效率
减少读取操作的 I/O 量
提高WiredTiger内存缓存的使用率,进一步提高查询速度
降低处理时间序列数据的复杂性
比较时间序列集合与常规集合
在常规集合中,数据作为块按顺序存储在磁盘上,从而优化了写入速度。但是,它需要为每个数据点建立一个索引,而该索引很快就会变得非常大。它还需要第二个索引,其中包含时间序列标识符和时间戳本身,以便用户可以查询单个序列。要读取此数据, MongoDB必须进程包含该数据的所有数据库和磁盘区块,即使某个区块仅包含一个相关文档。
此模型针对增删改查操作和频繁更新进行了优化。银行账户余额只需反映当前状态,因此每个账户持有人的文档都会随着信息的变化而更新。
将其与时间序列集合进行比较。时间序列集合按顺序写入数据,这意味着最近的事务可以保留在内存中,以便更快地检索。由于它们是按顺序写入的,因此文档会存储在一起,因此在文档不再位于内存中后,无需读取每个磁盘区块。数据按metaField
进行索引,从而使索引小得多。
分桶的工作原理
当您创建时间序列集合时, MongoDB会自动创建一个system.buckets
系统集合。 MongoDB对同时具备以下条件的文档进行分组:
相同的
metaField
值,应唯一标识时间序列。如果metaField
是对象或大量,则仅当所有对象字段或大量元素都匹配时, MongoDB才会进行分组。timeField
值相近的值。时间序列集合的granularity
、bucketMaxSpanSeconds
和bucketRoundingSeconds
参数控制每个存储桶涵盖的时间跨度。有关详细信息,请参阅设置时间序列数据的粒度。
示例, MongoDB在同一小时内以seconds
的粒度对文档进行存储桶。如果存储桶文档metaField
值为sensorA
且timeField
值为2024-08-01T18:23:21Z
的文档,则metaField
为sensorB
的传入文档无论何时都会放入单独的存储桶中。仅当来自sensorA
的传入文档的timeField
介于2024-08-01T18:00:00Z
和2024-08-01T18:59:59Z
之间时,该文档才会放入同一存储桶中。
如果时间为 2023-03-27T16:24:35Z
的文档不适合现有存储桶,MongoDB 将创建一个新存储桶,其最小时间为 2023-03-27T16:00:00Z
,最大时间为 2023-03-27T19:59:59Z
。
注意
您可以修改时间序列集合的粒度,但只能从更精细的测量更改为更粗略的测量,例如将存储桶覆盖范围从分钟扩展到小时。这会更新集合的视图定义,但不会更改数据在现有存储桶中的存储方式。
元字段如何影响分桶
由于metaField
值必须完全匹配才能对文档进行群组,因此时间序列集合中存储桶的数量取决于唯一metaField
值的数量。具有细粒度或不断变化的metaField
值的集合会生成许多稀疏填充的短期存储桶。这会导致存储和查询效率。
示例,在以下文档中, metadata
是metaField
不错的选择,因为它可以轻松查询来自给定天气传感器的数据。 MongoDB使用这些字段,将来自单个传感器的读数存储在一起。
{ timestamp: ISODate("2021-05-18T00:00:00.000Z"), metadata: { sensorId: 5578, type: 'temperature' }, temp: 12, _id: ObjectId("62f11bbf1e52f124b84479ad") }
存储桶目录
存储桶目录是WiredTiger中的专门内存缓存。它跟踪存储桶以最大限度地减少延迟并协调并发写入。
对于每个打开的存储桶,目录维护metaField
、活跃写入者、涵盖的时间跨度、文档数量、大小和最近操作等信息。由于MongoDB会为具有不同metaField
的文档创建单独的存储桶,因此通常会同时打开多个存储桶。
为了避免争用条件导致的不一致,在执行冲突操作时,可能会关闭存储桶并将其从存储桶目录中删除。重新启动mongod
会关闭所有存储桶并重置存储桶目录。
创建
如果没有适合传入文档的存储桶, MongoDB会创建一个新存储桶。当满足以下任一条件时,就会发生这种情况:
文档
metaField
与任何活动存储桶都不匹配。文档时间戳超出所有活动存储桶的范围。
文档超过所有活动存储桶的剩余大小或文档限制。
新存储桶的起始时间戳根据集合的粒度向下取整。这可以处理时间戳无序的文档连续到达的情况。
关闭
MongoDB会在以下任一情况下关闭存储桶:
时间已向前或向后移动超过了覆盖的时间跨度,如传入文档时间戳超出存储桶边界所示。这些边界由集合的粒度设置决定。
存储桶已达到文档限制(默认为1000 )。
存储桶已超过其存储大小限制。在以下情况下会发生这种情况:
大小超过允许的最大值(默认为125 KiB)。
文档数量低于最小数量(默认为10 ),大小低于12 MiB。
这是一设立内部限制,可在数据由较少但较大的文档组成时优化性能。
活动存储桶设立不符合允许的存储引擎缓存大小。您可以使用
collStats
数据库命令查看此信息。
存储桶目录超过其允许的总内存分配(默认,可用系统内存的2.5 %)
冲突操作(例如数据数据块迁移或更新)会更改存储桶的磁盘上状态。
mongod
重新启动。这将关闭所有存储桶。
删除
MongoDB在以下情况下删除存储桶:
其允许的最大时间戳小于当前时间减去集合的
expireAfterSeconds
参数。这相当于TTL集合的生存时间。delete
或db.collection.deleteMany()
命令删除存储桶中的最后文档。