2012-10-08 82 views
2

我在通过C#使用MongoDB聚合框架时遇到了性能问题。在C#中执行时,通过Mongo Shell快速运行的聚合需要永久性。通过C#使用MongoDB聚合框架时的性能问题

试图调用通过C#的框架之前,我通过蒙戈shell中执行下列聚合检查一切正常:

db.runCommand(
    { 
     aggregate: "actions", 
     pipeline : 
     [ 
      { $match : { CustomerAppId : "f5357224-b1a8-4f1a-8ea2-a06a00ca597a", ActionName : "install"}}, 
      { $group : { _id : { CustomerAppId:"$CustomerAppId",ActionDate:"$ActionDate" }, count : { $sum : 1 } }} 
     ] 
    }); 

在< 500ms的执行的脚本和返回预期的大约200个结果( CustomerAppId被定义为数据库中的一个字符串,不可能在集合框架中使用GUID)。

然后,我移植了相同的脚本到C#:

var pipeline = new BsonArray 
     { 
      new BsonDocument 
       { 
        { 
         "$match", 
         new BsonDocument 
          { 
           {"CustomerAppId", "f5357224-b1a8-4f1a-8ea2-a06a00ca597a"}, 
           {"ActionName", "install"} 
          } 
        }, 
        { "$group", 
         new BsonDocument 
          { 
           { "_id", new BsonDocument 
              { 
               { 
                "CustomerAppId","$CustomerAppId" 
               }, 
               { 
                "ActionName","$ActionName" 
               } 
              } 

           }, 
           { 
            "Count", new BsonDocument 
               { 
                { 
                 "$sum", 1 
                } 
               } 
           } 
          } 
        } 
      } 
     }; 


var command = new CommandDocument 
{ 
    { "aggregate", "actions" }, 
    { "pipeline", pipeline } 
}; 

(请让我知道是否有写在C#中聚集:)更简单的方法)

我敢执行像这样的:

var result = db.RunCommand(command); 

的问题是,它杀死服务器:该CPU和内存使用走一路上扬。当我检查db.currentOp(),我可以看到聚集的操作,但我最终还是把它用db.killOp(1281546)杀:

"opid" : 1281546, 
"active" : true, 
"secs_running" : 294, 
"op" : "query", 
"ns" : "database.actions", 
"query" : { 
     "aggregate" : "actions", 
     "pipeline" : [ 
       { 
         "$match" : { 
           "CustomerAppId" : "f5357224-b1a8-4f1a-8ea2-a06a00ca597a", 
           "ActionName" : "install" 
         }, 
         "$group" : { 
           "_id" : { 
             "CustomerAppId" : "$CustomerAppId", 
             "ActionName" : "$ActionName" 
           }, 
           "Count" : { 
             "$sum" : 1 
           } 
         } 
       } 
     ] 
}, 

对我而言,操作看起来完全罚款和类似脚本我直接从mongo shell运行。感觉像通过C#运行聚合会导致MongoDB错过索引,并且它正在对集合中所有大约600万个文档执行表扫描。

任何想法?

更新:日志

得益于Cirrus的建议,我启用了详细日志记录,然后用尾巴来获取查询。和他们是不同的!所以我认为我的C#端口有问题。有关如何正确格式化查询的任何想法?

当通过外壳执行查询:

Mon Oct 8 15:00:13 [conn1] run command database.$cmd { aggregate: "actions", pipeline: [ { $match: { CustomerAppId: "f5357224-b1a8-4f1a-8ea2-a06a00ca597a", ActionName: "install" } }, { $group: { _id: { CustomerAppId: "$CustomerAppId", ActionDate: "$ActionDate" }, count: { $sum: 1.0 } } } ] } 
Mon Oct 8 15:00:13 [conn1] command database.$cmd command: { aggregate: "actions", pipeline: [ { $match: { CustomerAppId: "f5357224-b1a8-4f1a-8ea2-a06a00ca597a", ActionName: "install" } }, { $group: { _id: { CustomerAppId: "$CustomerAppId", ActionDate: "$ActionDate" }, count: { $sum: 1.0 } } } ] } ntoreturn:1 keyUpdates:0 locks(micros) r:27944 reslen:12705 29ms 

当通过C#执行查询:

Mon Oct 8 15:00:16 [conn8] run command database.$cmd { aggregate: "actions", pipeline: [ { $match: { CustomerAppId: "f5357224-b1a8-4f1a-8ea2-a06a00ca597a", ActionName: "install" }, $group: { _id: { CustomerAppId: "$CustomerAppId", ActionDate: "$ActionDate" }, Count: { $sum: 1 } } } ] } 

下联丢失,我想因为查询未完成。

这里再次提供日志以方便比较。脚本到了,C#down:

Mon Oct 8 15:00:13 [conn1] run command database.$cmd { aggregate: "actions", pipeline: [ { $match: { CustomerAppId: "f5357224-b1a8-4f1a-8ea2-a06a00ca597a", ActionName: "install" } }, { $group: { _id: { CustomerAppId: "$CustomerAppId", ActionDate: "$ActionDate" }, count: { $sum: 1.0 } } } ] } 
Mon Oct 8 15:00:16 [conn8] run command database.$cmd { aggregate: "actions", pipeline: [ { $match: { CustomerAppId: "f5357224-b1a8-4f1a-8ea2-a06a00ca597a", ActionName: "install" }, $group: { _id: { CustomerAppId: "$CustomerAppId", ActionDate: "$ActionDate" }, Count: { $sum: 1 } } } ] } 
+2

你知道你已经使用ActionDate在C#版C#LINQ提供MongoDB的聚合框架,而不是到Action版本的shell版本吧?除此之外,在配置文件中使用“verbose = true”开启日志记录,并使用tail.exe日志文件。它会显示它在数据库上执行的实际查询。 – cirrus

+0

其实不行!我发誓我三重检查了一些事情,但我仍然设法想念它。但不幸的是执行速度仍然很慢。该索引包含ActionName,CustomerAppId和ActionDate。使用AppId&Date或AppId&ActionName从shell进行分组速度很快,但从代码来看,它们都很慢。感谢提供详细的建议。我得检查一下。 –

+0

不要忘记你可以upvote有用的意见,以及答案; – cirrus

回答

4

原来我正在格式化pipeline对象,不正确。 $ match和$ group都必须位于其自己的BsonDocument实例中。下面的代码似乎产生正确的输出:

var pipeline = new BsonArray 
     { 
      new BsonDocument 
       { 
        { 
         "$match", 
         new BsonDocument 
          { 
           {"CustomerAppId", "f5357224-b1a8-4f1a-8ea2-a06a00ca597a"}, 
           {"ActionName", "install"} 
          } 
        } 
      }, 
      new BsonDocument 
       { 
        { "$group", 
         new BsonDocument 
          { 
           { "_id", new BsonDocument 
              { 
               { 
                "CustomerAppId","$CustomerAppId" 
               }, 
               { 
                "ActionDate","$ActionDate" 
               } 
              } 

           }, 
           { 
            "Count", new BsonDocument 
               { 
                { 
                 "$sum", 1 
                } 
               } 
           } 
          } 
        } 
       } 
     }; 

我真的希望有一个在管道:)

+1

我也可以。我怀疑冗长可能会有所帮助,因为我最近一直在那里。驾驶员缺乏总体支持是不方便的。它更脆弱,意味着丑陋的参数替换。有一张票https://jira.mongodb.org/browse/CSHARP-383用于linq的聚合支持,但由于可以使用上面使用的方法,因此它已关闭。就我个人而言,我并不认为这是令人满意的,你也不会听到这种声音。如果你阅读评论,我不明白为什么它被关闭。它需要重新开放恕我直言。 – cirrus

+0

我最终编写了一个教程,其中显示了使用C#使用聚合框架的示例。希望人们可以复制并粘贴这些文件并使用它们来构建自己的管道。 http://mikaelkoskinen.net/post/mongodb-aggregation-framework-examples-c-csharp.aspx –

+0

@cirrus有一个开放的问题来支持linq到聚合框架在这里看到问题https://jira.mongodb.org /浏览/ CSHARP-601?JQL =项目%20%3D%20CSHARP%20于是%20resolution%20%3D%20Unresolved%20ORDER%20BY%20assignee%20ASC%2C%20priority%20DESC – Dreamwalker