向时间序列集合添加从节点索引
要提高 时间序列集合的查询性能,可以添加一个或多个二级索引以支持常见的时间序列查询模式。从 MongoDB 6.3开始,MongoDB 自动在 metaField
和 timeField
字段上为新集合创建复合索引。
注意
并非所有索引类型都受支持。有关不支持的索引类型的列表,请参阅时间序列集合二级索引的限制。
您可能希望创建额外的二级索引。考虑使用具有以下配置的天气数据集合:
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
字段上使用二级索引。在某些条件下,排序操作还可以在 metaField
和 timeField
字段上使用复合二级索引。
聚合管道阶段 $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.stage
为 DISTINCT_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()
方法。
创建 2dsphere 索引
从 6.0 版开始,您可以在 timeField
、metaField
或测量字段上创建 2dsphere 索引。
例如,以下操作在 location
字段上创建 2dsphere 索引:
例子
db.sensorData.createIndex({ "metadata.location": "2dsphere" })
此外,以下操作还会在测量字段上创建 2dsphere 索引:
例子
db.sensorData.createIndex({ "currentConditions.tempF": "2dsphere" })
注意
如果在时间序列集合上具有二级索引,并且您需要降级特征兼容性版本 (FCV),必须先删除与降级 FCV 不兼容的任何二级索引。有关详细信息,请参阅 setFeatureCompatibilityVersion
。