【发布时间】:2016-05-24 04:46:28
【问题描述】:
我直接在 Mongo(Robomongo、CLI 等)中对 select all items where field1=x, field2 =y, and field3=z 运行查询,并且对几十万个项目只用了不到一秒钟的时间:
db.items.find( {
$and: [
{ CreatingOrgId: 1 },
{ LocationId: 941 },
{ StatusId: 1}
]
} )
然后我尝试从 C# 驱动程序运行完全相同的东西,但它滞后了(只有“聚合过滤器”代码是相关的,其他一切都是为了上下文):
FilterDefinition<BsonDocument> locationsFilter; = Builders<BsonDocument>.Filter.Eq("LocationId", 941);
FilterDefinition<BsonDocument> orgFilter = Builders<BsonDocument>.Filter.Eq("CreatingOrgId", 1);
FilterDefinition<BsonDocument> statusFilter = Builders<BsonDocument>.Filter.Eq("StatusId", 1);
FilterDefinition<BsonDocument> aggregateFilter = locationsFilter & statusFilter & orgFilter;
List<ItemViewModel> stuffList = mongoItemsCollection
.Find(aggregateFilter)
.Project(x => Mapper.Map<BsonDocument, StuffViewModel>(x))
.ToListAsync().Result;
我的错误是什么?以下是 mongo 看到的查询:
编辑:看起来将项目映射到项目对象在某种程度上扼杀了我的查询。如果没有映射,它相当快(大量记录只需几秒钟),如下所示:
var rawItems = mongoItemsCollection
.Find(aggregateFilter)
.ToListAsync().Result;
编辑 2:看起来 automapper 是问题的重要部分(获取 bson“项目”对象并将其转换为 .NET 视图模型)。如果有人想回答,我仍然对 .NET --> mongo 查询本身的优化感兴趣(忽略自动映射器部分)。
【问题讨论】:
-
旁注:完全没有必要使用
$and:db.items.find({CreatingOrgId: 1, LocationId: 941, StatusId: 1})。据我所知,这些查询之间的字段顺序是不同的。假设您有一个索引:Order matters。因此,您应该根据索引的顺序重新排列过滤器。 -
感谢您的回复。在实践中,我实际上必须按 5 个字段进行过滤,所有这些字段都是可选的。所以像 ABCDE、A、BCD、CDE、D 等。我对细节很好奇,因为我不明白 ABCDE 上的索引是否可以处理字段 CD 中的搜索,例如。或者我是否需要每个可能组合的索引。但是,如果我正确理解您的链接,该示例非常清楚地表明 ABCDE 上的索引将处理所有子查询(例如前面提到的“CD”),只要它们按顺序排列即可。另外,是否存在需要 $and 的情况?
-
您的 C# 代码正在执行 ToListAsync,因此它正在访问所有结果并返回它们。在 CLI 上比较的更等效的测试是
.find().toArray(),否则它只会访问和返回 20 个结果(默认情况下)。如果结果集是“几十万个项目”,那将是一个很大的区别,尤其是如果结果不是仅索引并且必须从磁盘中检索。 -
看起来映射是杀死它的一部分,你说得有道理,会更新问题。
-
@sheilak 你能详细说明你的答案吗?我的控制器不是异步的,这就是我使用 .Result() 的原因 - 当我查看方法列表时,.toArrayAsync() 不是一个选项。我正在使用 C# 驱动程序 2.0。
标签: mongodb mongodb-query mongodb-.net-driver