我是MongoDB和NoSQL的新手,我正试图在一个巨大的数据集(大约5000万个文档)上运行查询
我在Windows 10主机上使用Docker运行最新版本的MongoDB,内存为64 GB。
我使用pymongo
来导入数据并运行查询,我也有Mongo Express
作为docker容器运行以查看导入的数据。
创建时间序列集合的语句是:
mydb.command('create', 'sensor_data', timeseries={
'timeField': 'collection_time',
'metaField': 'sensor'
})
每个文档看起来像这样:
{
"sensor": { "id": 1, "location":"Somewhere"},
"collection_time": datetime.strptime("2022/01/01 01:23:45 PM", '%Y/%m/%d %I:%M:%S %p'),
...
}
我已经能够使用Mongo Express
来验证数据是否已正确加载到MongoDB。
然后我尝试运行以下代码:
res = mycol.find({
"collection_time": {
"$gte": datetime.strptime("2021/01/01 12:00:00 AM", '%Y/%m/%d %I:%M:%S %p'),
"$lte": datetime.strptime("2022/02/01 12:00:00 AM", '%Y/%m/%d %I:%M:%S %p')
}
})
但是这个查询需要很长时间才能运行。
运行res.explain()
后,我可以看到该操作正在执行COLSCAN
而不使用索引。我甚至尝试手动创建一个索引上的'collection_time',但查询仍在做COLSCAN。我错过了什么?
更新1多亏了R2D2的解决方案,我已经为find()
工作了,但我不能让它为aggregate()
工作下面是我的代码:
res = mycol.aggregate([
{
"$match": {
"collection_time": {
"$gte": datetime.strptime("2021/01/01 12:00:00 AM", '%Y/%m/%d %I:%M:%S %p'),
"$lte": datetime.strptime("2022/02/01 12:00:00 AM", '%Y/%m/%d %I:%M:%S %p')
}
}
},
{"$group":
{
"_id": {
"year" : { "$year" : "$collection_time" },
"month" : { "$month" : "$collection_time" },
"day" : { "$dayOfMonth" : "$collection_time" },
},
"count":{ "$sum": 1}
}
}
], {hint: "collection_time_1" })
NameError: name 'hint' is not defined
将hint
放在引号中会产生错误:AttributeError: 'dict' object has no attribute '_txn_read_preference'
默认情况下,当您创建时间序列集合时,它对于存储时间序列数据是有效的,但是没有创建索引,您可以为时间序列集合创建二级索引以提高查询的性能,如果查询规划器没有选择某些已创建的索引,您可以使用索引名称向查询添加hint()(您可以使用db.collection.getIndexes()获得索引名称)
对于mongodb 3.6+,您也可以在聚合框架中使用提示,如下所示:
db.collection.aggregate(pipeline, {hint: "index_name"})