mongo???java???shell???????

Posted

技术标签:

【中文标题】mongo查询与java代码和shell花费不同的时间【英文标题】:mongo query which costs different time from java code and shell 【发布时间】:2015-04-10 06:25:06 【问题描述】:

我有一个 mongo 查询,它花费的时间与 java 代码和 shell 不同。 Java代码如下,

mongo服务器的版本是v2.6.5,v2.4.8版本没有问题。

DBObject obj = new BasicDBObject();
obj.put("accountId",accountId);
List<DBObject> listOr = new ArrayList<DBObject>();
listOr.add(new BasicDBObject("status", 11));
listOr.add(new BasicDBObject("status", 12));
obj.put("$or", listOr);
BasicDBObject andDB = new BasicDBObject();
andDB.append("$gt", 0);
andDB.append("$lt",4514185);
obj.put("currBoardId",andDB);
DBCursor cur = null;
cur = coll.find(obj,new BasicDBObject("currBoardId",1)).sort(new BasicDBObject("commentId",-1)).limit(10);

当我运行代码时,我可以从配置文件集合中获取慢查询记录。它显示“nscanned”:1566031 和“millis”:4724。

> db.system.profile.find().sort($natural:-1).limit(10);

"op" : "query", "ns" : "l_comment.comment", "query" : "$query" : "accountId" : NumberLong(4), "$or" : [ "状态“:11 ,“状态”:12 ],“currBoardId”:“$gt”:0,“$lt”:NumberLong(4514185),“$orderby”:“commentId”:- 1 ,“cursorid”:220355902849,“ntoreturn”:10,“ntoskip”:0,“nscanned”:1566031,“nscannedObjects”:1566031,“keyUpdates”:0,“numYield”:5,“lockStats”: “timeLockedMicros”:“r”:NumberLong(8921271),“w”:NumberLong(0),“timeAcquiringMicros”:“r”:NumberLong(14),“w”:NumberLong(2), “nreturned”:10,“responseLength”:410,“millis”:4724,“execStats”:“type”:“PROJECTION”,“works”:1566031,“yields”:12234,“unyields”:12234,“无效”:0,“高级”:10,“needTime”:0,“needFetch”:0,“isEOF”:0,“children”:[“type”:“FETCH”,“works”:1566031,“产量”:12234,“unyields”:12234,“无效”:0,“高级”:10,“needTime”:1566021,“needFetch”:0,“isEOF”: 0,“alreadyHasObj”:0,“forcedFetches”:0,“matchTested”:10,“children”:[“type”:“IXSCAN”,“works”:1566031,“yields”:12234,“unyields”: 12234,“无效”:0,“高级”:1566031,“needTime”:0,“needFetch”:0,“isEOF”:0,“keyPattern”:“ commentId:-1.0 ”,“isMultiKey”:0 ,“boundsVerbose”:“字段#0 ['commentId']:[MaxKey,MinKey]”,“yieldMovedCursor”:0,“dupsTested”:0,“dupsDropped”:0,“seenInvalidated”:0,“matchTested”: 0,“keysExamined”:1566031,“孩子”:[] ] ],“ts”:ISODate(“2015-02-10T08:51:16.195Z”),“客户”:“192.168.66.103”, “所有用户”:[],“用户”:“”

但是当我从 shell 运行查询时,它返回很快。

db.comment.find( "accountId" : NumberLong(4), "$or" : [    "status" : 11 ,    "status" : 12  ], "currBoardId" :  "$gt" : 0, "$lt" : NumberLong(4514185) ).sort(commentId:-1).limit(10)

下面是它的解释输出。它显示查询扫描 10517 条记录并使用 109 毫秒。 为什么会这样,我该如何改进代码?

感谢任何提示和帮助。


    "clauses" : [
        
            "cursor" : "BtreeCursor idx_atst",
            "isMultiKey" : false,
            "n" : 10,
            "nscannedObjects" : 10517,
            "nscanned" : 10517,
            "scanAndOrder" : true,
            "indexOnly" : false,
            "nChunkSkips" : 0,
            "indexBounds" : 
                "accountId" : [
                    [
                        NumberLong(4),
                        NumberLong(4)
                    ]
                ],
                "rootId" : [
                    [
                        
                            "$maxElement" : 1
                        ,
                        
                            "$minElement" : 1
                        
                    ]
                ],
                "status" : [
                    [
                        
                            "$minElement" : 1
                        ,
                        
                            "$maxElement" : 1
                        
                    ]
                ],
                "type" : [
                    [
                        
                            "$minElement" : 1
                        ,
                        
                            "$maxElement" : 1
                        
                    ]
                ]
            
        ,
        
            "cursor" : "BtreeCursor ",
            "isMultiKey" : false,
            "n" : 0,
            "nscannedObjects" : 0,
            "nscanned" : 0,
            "scanAndOrder" : true,
            "indexOnly" : false,
            "nChunkSkips" : 0,
            "indexBounds" : 
                "accountId" : [
                    [
                        NumberLong(4),
                        NumberLong(4)
                    ]
                ],
                "rootId" : [
                    [
                        
                            "$maxElement" : 1
                        ,
                        
                            "$minElement" : 1
                        
                    ]
                ],
                "status" : [
                    [
                        
                            "$minElement" : 1
                        ,
                        
                            "$maxElement" : 1
                        
                    ]
                ],
                "type" : [
                    [
                        
                            "$minElement" : 1
                        ,
                        
                            "$maxElement" : 1
                        
                    ]
                ]
            
        
    ],
    "cursor" : "QueryOptimizerCursor",
    "n" : 10,
    "nscannedObjects" : 10517,
    "nscanned" : 10517,
    "nscannedObjectsAllPlans" : 31574,
    "nscannedAllPlans" : 31574,
    "scanAndOrder" : false,
    "nYields" : 246,
    "nChunkSkips" : 0,
    "millis" : 109,
    "server" : "app-sz-2-3.sz.chosk.net:27017",
    "filterSet" : false,
    "stats" : 
        "type" : "KEEP_MUTATIONS",
        "works" : 10529,
        "yields" : 246,
        "unyields" : 246,
        "invalidates" : 0,
        "advanced" : 10,
        "needTime" : 10519,
        "needFetch" : 0,
        "isEOF" : 0,
        "children" : [
            
                "type" : "OR",
                "works" : 10529,
                "yields" : 246,
                "unyields" : 246,
                "invalidates" : 0,
                "advanced" : 10,
                "needTime" : 10519,
                "needFetch" : 0,
                "isEOF" : 0,
                "dupsTested" : 10,
                "dupsDropped" : 0,
                "locsForgotten" : 0,
                "matchTested_0" : 0,
                "matchTested_1" : 0,
                "children" : [
                    
                        "type" : "SORT",
                        "works" : 10529,
                        "yields" : 246,
                        "unyields" : 246,
                        "invalidates" : 0,
                        "advanced" : 10,
                        "needTime" : 10518,
                        "needFetch" : 0,
                        "isEOF" : 1,
                        "forcedFetches" : 0,
                        "memUsage" : 4675,
                        "memLimit" : 33554432,
                        "children" : [
                            
                                "type" : "FETCH",
                                "works" : 10518,
                                "yields" : 246,
                                "unyields" : 246,
                                "invalidates" : 0,
                                "advanced" : 1909,
                                "needTime" : 8608,
                                "needFetch" : 0,
                                "isEOF" : 1,
                                "alreadyHasObj" : 0,
                                "forcedFetches" : 0,
                                "matchTested" : 1909,
                                "children" : [
                                    
                                        "type" : "IXSCAN",
                                        "works" : 10518,
                                        "yields" : 246,
                                        "unyields" : 246,
                                        "invalidates" : 0,
                                        "advanced" : 10517,
                                        "needTime" : 0,
                                        "needFetch" : 0,
                                        "isEOF" : 1,
                                        "keyPattern" : " accountId: 1, rootId: -1.0, status: 1, type: 1 ",
                                        "isMultiKey" : 0,
                                        "boundsVerbose" : "field #0['accountId']: [4, 4], field #1['rootId']: [MaxKey, MinKey], field #2['status']: [MinKey, MaxKey], field #3['type']: [MinKey, MaxKey]",
                                        "yieldMovedCursor" : 0,
                                        "dupsTested" : 0,
                                        "dupsDropped" : 0,
                                        "seenInvalidated" : 0,
                                        "matchTested" : 0,
                                        "keysExamined" : 10517,
                                        "children" : [ ]
                                    
                                ]
                            
                        ]
                    ,
                    
                        "type" : "SORT",
                        "works" : 0,
                        "yields" : 246,
                        "unyields" : 246,
                        "invalidates" : 0,
                        "advanced" : 0,
                        "needTime" : 0,
                        "needFetch" : 0,
                        "isEOF" : 0,
                        "forcedFetches" : 0,
                        "memUsage" : 0,
                        "memLimit" : 33554432,
                        "children" : [
                            
                                "type" : "FETCH",
                                "works" : 0,
                                "yields" : 246,
                                "unyields" : 246,
                                "invalidates" : 0,
                                "advanced" : 0,
                                "needTime" : 0,
                                "needFetch" : 0,
                                "isEOF" : 0,
                                "alreadyHasObj" : 0,
                                "forcedFetches" : 0,
                                "matchTested" : 0,
                                "children" : [
                                    
                                        "type" : "IXSCAN",
                                        "works" : 0,
                                        "yields" : 246,
                                        "unyields" : 246,
                                        "invalidates" : 0,
                                        "advanced" : 0,
                                        "needTime" : 0,
                                        "needFetch" : 0,
                                        "isEOF" : 0,
                                        "keyPattern" : "",
                                        "isMultiKey" : 0,
                                        "boundsVerbose" : "field #0['accountId']: [4, 4], field #1['rootId']: [MaxKey, MinKey], field #2['status']: [MinKey, MaxKey], field #3['type']: [MinKey, MaxKey]",
                                        "yieldMovedCursor" : 0,
                                        "dupsTested" : 0,
                                        "dupsDropped" : 0,
                                        "seenInvalidated" : 0,
                                        "matchTested" : 0,
                                        "keysExamined" : 0,
                                        "children" : [ ]
                                    
                                ]
                            
                        ]
                    
                ]
            
        ]
    

【问题讨论】:

查询的不同之处在于,您在 Java 代码中使用new BasicDBObject("currBoardId",1) 限制返回的键,剥离结果应该需要一些时间,但不应更改扫描的对象。很有趣。 这让我很困惑 你能在java中显示变量accountId的定义吗? 所有参数都在慢查询记录中,我在shell中运行从那里复制的查询。 从 Java 运行的查询和从 shell 运行的查询使用了不同的索引。从 Java 运行的查询使用索引来处理排序 "commentId" : -1 ,而从 shell 运行的查询使用索引来处理实际的查询谓词。这解释了为什么 Java 查询的 nscanned 比 shell 查询高得多。这种索引选择是否每次都会发生?还是 Java 查询仅在某些时候选择排序索引?你需要其他的排序索引吗?能否将排序字段添加到 shell 查询的索引中? 【参考方案1】:

在您的 Shell 查询中,您在 $lt$or 语句中使用 NumberLong(4514185)。但是在您的 Java 查询中,您使用的是 andDB.append("$lt", 4514185); 这是一个 Integer,因此您的 Java 查询需要一个从 Integer 到 Long 的类型转换。尝试在您的号码后使用 andDB.append("$lt", 4514185L);L 以创建带有 Long 的查询。 accountId 也应该是 Long

【讨论】:

在我的代码中,参数类型是 Long ,我只是直接写了它们以显示示例。【参考方案2】:

在 wdberkeley 的提示下,我注意到了索引。我不明白mongodb是如何选择索引的,但是在我添加另一个索引之后,来自java代码的查询会选择正确的索引。即使我删除后来添加的索引,它仍然使用正确的索引。所以如果查询没有使用我们想要的索引,我们应该使用hint来分配我们想要的索引。

我添加的索引:

ensureIndex("accountId" : -1,"type" : 1,"status" : 1,"name" : "idx_ats");

【讨论】:

以上是关于mongo???java???shell???????的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB - The mongo Shell, Configure the mongo Shell

MongoDB - The mongo Shell, Write Scripts for the mongo Shell

MongoDB - The mongo Shell, Access the mongo Shell Help

MongoDB - The mongo Shell, Data Types in the mongo Shell

mongo shell

Errr 'mongo.js:L112 错误:无法在 src/mongo/shell/mongo.js:L112 连接到服务器 127.0.0.1:27017'