关于时间序列数据
MongoDB 在内部通过根据时间序列集合中的共同metaField
值对文档进行分组来优化时间序列数据。选择一个有用的值可以显著优化存储密度和查询性能。更多信息,请参见metaFields.
时间序列数据的属性
时间序列数据具有一些属性,使其与其他数据格式区分开来
文档按顺序到达,需要频繁进行插入操作来追加它们。
更新操作很少,因为每个文档代表一个时间点。
如果您的应用程序受益于拥有广泛的记录,则删除操作很少。
数据按时间和标识符(如股票代码)索引,该标识符标识它所属的唯一时间序列。
数据量很大,因为每个单独的时间序列都需要一个庞大且不断增长的大量文档。
为了考虑这些因素,MongoDB使用一种专门的列式格式,将每个时间序列的文档分组在一起。这有以下好处
减少存储和索引大小
提高查询效率
减少读取操作的I/O
增加对WiredTiger内存缓存的利用率,进一步提高查询速度
简化处理时间序列数据的工作复杂度
比较时间序列集合与常规集合
在常规集合中,数据按顺序存储在磁盘上的块中,优化了写入速度。然而,它需要为每个数据点创建一个索引,这会迅速增长得非常大。它还需要第二个索引,其中包含时间序列标识符和自身的时间戳,以便用户可以查询单个序列。为了读取这些数据,MongoDB必须处理包含它的所有数据库和磁盘块,即使一个块只包含一个相关的文档。
此模型优化了CRUD操作和频繁的更新。银行账户余额只需要反映当前状态,因此每个账户持有人的文档会随着信息的更改而更新。
将此与时间序列集合进行比较。时间序列集合按顺序写入数据,这意味着最近的事务可以保留在内存中以便更快地检索。由于它们按顺序写入,因此文档存储在一起,因此不需要在文档不再在内存后读取每个磁盘块。数据按metaField
索引,导致索引大小更小。
如何进行桶分区
当你创建一个时间序列集合时,MongoDB会自动创建一个system.buckets
系统集合。MongoDB将具有以下两个属性
具有相同
metaField
值(该值应唯一标识时间序列)的文档分组。如果metaField
是一个对象或数组,MongoDB只有在所有对象字段或数组元素匹配的情况下才会进行分组。彼此时间相近的
timeField
值。时间序列集合的granularity
、bucketMaxSpanSeconds
和bucketRoundingSeconds
参数控制每个桶覆盖的时间跨度。更多信息,请参阅设置时间序列数据粒度。
例如,如果粒度为秒
,MongoDB会将同一小时的文档归入一个桶。如果一个桶包含一个具有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
值的数量。具有细粒度或变化的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 在以下任一情况下关闭桶
删除
MongoDB在以下情况下删除一个桶:
它的最大允许时间戳小于当前时间减去集合的
expireAfterSeconds
参数。这相当于TTL集合的生存时间。delete
或db.collection.deleteMany()
命令删除桶中的最后一个文档。