Docs 菜单

Docs 主页开发应用程序MongoDB Manual

向时间序列集合添加从节点索引

在此页面上

  • 使用二级索引提高排序性能
  • 时间序列集合的最后一点查询
  • 为时间序列集合指定索引提示
  • MongoDB 6.0 及更早版本中的时间序列二级索引

要提高时间序列集合的查询性能,请添加一个或多个二级索引以支持常见的时间序列查询模式。从 MongoDB 6.3 开始,MongoDB 自动在 metaFieldtimeField 字段上为新集合创建复合索引

注意

并非所有索引类型都受支持。有关不支持的索引类型的列表,请参阅时间序列集合二级索引的限制

您可能希望创建额外的二级索引。考虑使用具有以下配置的天气数据集合:

db.createCollection(
"weather",
{
timeseries: {
timeField: "timestamp",
metaField: "metadata"
}})

在每个天气数据文档中,metadata 字段值是一个子文档,其中包含天气传感器 ID 和类型的字段:

{
"timestamp": ISODate("2021-05-18T00:00:00.000Z"),
"metadata": {
"sensorId": 5578,
"type": "temperature"
},
"temp": 12
}

集合的默认复合索引会对整个 metadata 子文档进行索引,因此该索引仅用于 $eq 查询。通过对特定的 metadata 字段建立索引,您可以提高其他查询类型的查询性能。

例如,此 $in 查询受益于 metadata.type 的二级索引:

{ metadata.type:{ $in: ["temperature", "pressure"] }}

提示

请参阅:

对时间序列集合的排序操作可以在 timeField 字段上使用二级索引。在某些条件下,排序操作还可以在 metaFieldtimeField 字段上使用复合二级索引。

聚合管道阶段 $match$sort 确定时间序列集合可以使用哪些索引。索引可用于以下场景:

  • { <timeField>: ±1 } 上的排序使用 <timeField> 上的二级索引

  • { <metaField>: ±1, timeField: ±1 } 的排序会在 { <metaField>: ±1, timeField: ±1 } 上使用默认复合索引

  • <metaField> 上具有点谓词时,{ <timeField>: ±1 } 上的排序使用 { metaField: ±1, timeField: ±1 } 上的二级索引

例如,以下 sensorData 集合包含来自天气传感器的测量值:

db.sensorData.insertMany( [ {
"metadata": {
"sensorId": 5578,
"type": "omni",
"location": {
type: "Point",
coordinates: [-77.40711, 39.03335]
}
},
"timestamp": ISODate("2022-01-15T00:00:00.000Z"),
"currentConditions": {
"windDirection": 127.0,
"tempF": 71.0,
"windSpeed": 2.0,
"cloudCover": null,
"precip": 0.1,
"humidity": 94.0,
}
},
{
"metadata": {
"sensorId": 5578,
"type": "omni",
"location": {
type: "Point",
coordinates: [-77.40711, 39.03335]
}
},
"timestamp": ISODate("2022-01-15T00:01:00.000Z"),
"currentConditions": {
"windDirection": 128.0,
"tempF": 69.8,
"windSpeed": 2.2,
"cloudCover": null,
"precip": 0.1,
"humidity": 94.3,
}
},
{
"metadata": {
"sensorId": 5579,
"type": "omni",
"location": {
type: "Point",
coordinates: [-80.19773, 25.77481]
}
},
"timestamp": ISODate("2022-01-15T00:01:00.000Z"),
"currentConditions": {
"windDirection": 115.0,
"tempF": 88.0,
"windSpeed": 1.0,
"cloudCover": null,
"precip": 0.0,
"humidity": 99.0,
}
}
]
)

timestamp 字段上创建二级单字段索引:

db.sensorData.createIndex( { "timestamp": 1 } )

以下对 timestamp 字段的排序操作使用二级索引来提高性能:

db.sensorData.aggregate( [
{ $match: { "timestamp" : { $gte: ISODate("2022-01-15T00:00:00.000Z") } } },
{ $sort: { "timestamp": 1 } }
] )

要确认排序操作使用了二级索引,请使用 .explain( "executionStats" ) 选项再次运行该操作:

db.sensorData.explain( "executionStats" ).aggregate( [
{ $match: { "timestamp": { $gte: ISODate("2022-01-15T00:00:00.000Z") } } },
{ $sort: { "timestamp": 1 } }
] )

在时间序列数据中,最新数据点查询会返回给定字段具有最新时间戳的数据点。对于时间序列集合,最新数据点查询会获取每个唯一元数据值的最新测量值。例如,您可能想要获取所有传感器的最新温度读数。可以通过创建以下任一索引来提升最新数据点查询的性能:

{ "metadata.sensorId": 1, "timestamp": 1 }
{ "metadata.sensorId": 1, "timestamp": -1 }
{ "metadata.sensorId": -1, "timestamp": 1 }
{ "metadata.sensorId": -1, "timestamp": -1 }

注意

最新数据点查询在使用 DISTINCT_SCAN 优化 时可实现最高性能。仅当 timeField 上的索引为降序时,才可以使用此优化。

以下命令创建一个复合二级索引,metaField 上的索引为升序,timeField 上的索引为降序:

db.sensorData.createIndex( { "metadata.sensorId": 1, "timestamp": -1 } )

以下最新数据点查询示例使用了上文中创建的降序 timeField 复合二级索引:

db.sensorData.aggregate( [
{
$sort: { "metadata.sensorId": 1, "timestamp": -1 }
},
{
$group: {
_id: "$metadata.sensorId",
ts: { $first: "$timestamp" },
temperatureF: { $first: "$currentConditions.tempF" }
}
}
] )

要确认最新数据点查询是否使用了二级索引,请使用 .explain( "executionStats" ) 再次运行该操作:

db.getCollection( 'sensorData' ).explain( "executionStats" ).aggregate( [
{
$sort: { "metadata.sensorId": 1, "timestamp": -1 }
},
{
$group: {
_id: "$metadata.sensorId",
ts: { $first: "$timestamp" },
temperatureF: { $first: "$currentConditions.tempF" }
}
}
] )

winningPlan.queryPlan.inputStage.stageDISTINCT_SCAN,表示使用了该索引。有关 Explain Plan 输出的更多信息,请参阅 Explain 结果

索引提示导致 MongoDB 使用特定的索引进行查询。如果在提示中指定了一个索引,对时间序列集合的某些操作只能利用该索引。

例如,以下查询会促使 MongoDB 使用 timestamp_1_metadata.sensorId_1 索引:

db.sensorData.find( { "metadata.sensorId": 5578 } ).hint( "timestamp_1_metadata.sensorId_1" )

在时间序列集合上,您可以使用索引名称或索引键模式指定提示。要获取集合上的索引名称,请使用 db.collection.getIndexes() 方法。

6.3 版本中的新功能

从 MongoDB 6.3 开始,您可以为时间序列集合创建部分TTL 索引。您只能对 metaField 进行筛选。

如果集合不使用 expireAfterSeconds 选项使文档过期,则创建部分 TTL 索引只会为匹配文档设置过期时间。如果集合对所有文档使用 expireAfterSeconds,则部分 TTL 索引可以让匹配文档更快过期。

6.0 版本中的新功能

从 MongoDB 6.0 开始,您可以

注意

如果 时间序列集合 上有 二级索引 ,并且需要降级特征兼容性版本 (fCV),则必须先删除与降级 fCV 不兼容的所有二级索引。请参阅setFeatureCompatibilityVersion

← 设置时间序列数据的粒度