Mongo查找查询需要2分钟

时间:2017-05-16 08:45:48

标签: node.js mongodb mongodb-query node-mongodb-native

我在一个集合中有大约75,000个文档。

数据库的总大小约为45GB 在75k文档中,大约45k是每个900 KB(大约42 GB),剩下的文档大约每个120 KB。

每个文档都映射到其他集合中的custId ObjectId,并且timestamp都已编入索引。

现在我需要为上个月的特定custId获取文档。 计数约为5500个文档。此custId的文档较小,大小约为120 KB。

以下是我的问题:

db.mycollection.find(
{
    custId:ObjectId("CUST_OBJECT_ID_HERE"),
    timestamp:{$gte:one_month_ago_date, $lt:current_date}
}).sort({timestamp:-1})

查询仍需要2分钟才能获取所有记录。是因为文件数量还是较大文件的大小?有没有办法解决这个问题?

注意: 从nodejs触发查询需要2分钟。如果我在mongo shell上触发它,它会很快返回,但可能是因为它刚刚获取前50条记录。当我将.count()附加到mongo shell上的查询时,用计数返回需要2分钟。

更新
索引详细信息:

"wiredTiger" : {
    "nindexes" : 3,
    "totalIndexSize" : 2396160,
    "indexSizes" : {
        "_id_" : 1138688,
        "custId_1" : 598016,
        "timestamp_1" : 659456
    }
}

解释输出:(有分类)

{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "mydb.mycollection",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "$and" : [
                {
                    "custId" : {
                        "$eq" : ObjectId("CUST_OBJECT_ID_HERE")
                    }
                },
                {
                    "timestamp" : {
                        "$lt" : ISODate("2017-05-15T14:20:04.393Z")
                    }
                },
                {
                    "timestamp" : {
                        "$gte" : ISODate("2017-04-15T14:20:04.393Z")
                    }
                }
            ]
        },
        "winningPlan" : {
            "stage" : "FETCH",
            "filter" : {
                "custId" : {
                    "$eq" : ObjectId("CUST_OBJECT_ID_HERE")
                }
            },
            "inputStage" : {
                "stage" : "IXSCAN",
                "keyPattern" : {
                    "timestamp" : 1
                },
                "indexName" : "timestamp_1",
                "isMultiKey" : false,
                "isUnique" : false,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 1,
                "direction" : "backward",
                "indexBounds" : {
                    "timestamp" : [
                        "(new Date(1494858004393), new Date(1492266004393)]"
                    ]
                }
            }
        },
        "rejectedPlans" : [
            {
                "stage" : "SORT",
                "sortPattern" : {
                    "timestamp" : -1
                },
                "inputStage" : {
                    "stage" : "SORT_KEY_GENERATOR",
                    "inputStage" : {
                        "stage" : "FETCH",
                        "filter" : {
                            "$and" : [
                                {
                                    "timestamp" : {
                                        "$lt" : ISODate("2017-05-15T14:20:04.393Z")
                                    }
                                },
                                {
                                    "timestamp" : {
                                        "$gte" : ISODate("2017-04-15T14:20:04.393Z")
                                    }
                                }
                            ]
                        },
                        "inputStage" : {
                            "stage" : "IXSCAN",
                            "keyPattern" : {
                                "custId" : 1
                            },
                            "indexName" : "custId_1",
                            "isMultiKey" : false,
                            "isUnique" : false,
                            "isSparse" : false,
                            "isPartial" : false,
                            "indexVersion" : 1,
                            "direction" : "forward",
                            "indexBounds" : {
                                "custId" : [
                                    "[ObjectId('CUST_OBJECT_ID_HERE'), ObjectId('CUST_OBJECT_ID_HERE')]"
                                ]
                            }
                        }
                    }
                }
            }
        ]
    },
    "serverInfo" : {
        "host" : "test-machine",
        "port" : 27017,
        "version" : "3.2.12",
        "gitVersion" : "REMOVED_BY_OP"
    },
    "ok" : 1
}

3 个答案:

答案 0 :(得分:3)

这就是索引的用途!

为timestamp和custId创建索引(复合索引,两者都是最有效的),你就可以了。由于按时间戳排序,在复合索引中,使时间戳成为第一个(顺序很重要)

这是在mongo中创建复合索引的代码:

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const userSchema = new Schema({
    //...
});

userSchema.index({timestamp: 1, custId: 1});

mongoose.model('User', userSchema);
module.exports = userSchema;

答案 1 :(得分:1)

试试这个索引:

db.mycollection.createIndex({custId:1,timestamp:1}, {background:true})

答案 2 :(得分:0)

以上答案都是完全正确的。只要加入我的2美分。这个答案在很大程度上取决于您可以使用的内存,以及您需要返回的信息是“实时”还是信息可以以某种方式缓存。

Mongodb因内存使用而臭名昭着。 (我喜欢mongodb,但记忆是阿喀琉斯之踵)。其次,如上所述,您可以采取任何措施来改进查询结果之前进行查询是一个很大的时间,读取和核心使用。在存储文档时,您可能(或将会)找到正确设置的Redis缓存,这将极大地帮助您降低响应时间。

显然,这需要内存,在您的情况下需要平衡(包括负载平衡)。它是内存,速度和磁盘使用的适当组合(即使它是SSD),这将帮助您平衡这些查询请求与系统的要求。

希望有所帮助。