将二级索引添加到时间序列集合
为了提高对时间序列集合的查询性能,添加一个或多个二级索引以支持常见的时序查询模式。从MongoDB 6.3开始,MongoDB会自动为新集合在metaField
和timeField
字段上创建一个复合索引。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 }
按照
{ <timeField>: ±1 }
排序在有<metaField>
上的点谓词时,使用{ 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
,这表明使用了索引。有关解释计划输出的更多信息,请参阅解释结果。
为时间序列集合指定索引提示
索引提示使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
。