首页 > 数据库 > Mongodb > MongoDB慢查询问题解决
2015
12-09

MongoDB慢查询问题解决

现象

App医生profile页数据加载不出来。 经查,是mongodb出现慢查询现象。

> db.users.find({phoneNum:"18601163270"}).explain()
{
    "cursor" : "BasicCursor",
    "isMultiKey" : false,
    "n" : 1,
    "nscannedObjects" : 43941,
    "nscanned" : 43941,
    "nscannedObjectsAllPlans" : 43941,
    "nscannedAllPlans" : 43941,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 343,
    "nChunkSkips" : 0,
    "millis" : 669,
    "server" : "MONGODB-2:27017",
    "filterSet" : false
}

而在同样数据量的测试服务器上则millis只需要38ms。

分析

对比两台服务器的db.stats()发现extentFreeList差别较大。

慢查询的生产服务器:

> db.stats()
{
    "db" : "web",
    "collections" : 37,
    "objects" : 697650,
    "avgObjSize" : 2776.3565340786927,
    "dataSize" : 1936925136,
    "storageSize" : 2202255360,
    "numExtents" : 166,
    "indexes" : 55,
    "indexSize" : 148312640,
    "fileSize" : 4226809856,
    "nsSizeMB" : 16,
    "dataFileVersion" : {
        "major" : 4,
        "minor" : 6
    },
    "extentFreeList" : {
        "num" : 78,
        "totalSize" : 1201172480
    },
    "ok" : 1
}

速度正常的测试服务器:

> db.stats()
{
    "db" : "web",
    "collections" : 36,
    "objects" : 696467,
    "avgObjSize" : 2784.906880010108,
    "dataSize" : 1939595740,
    "storageSize" : 2513326080,
    "numExtents" : 162,
    "indexes" : 52,
    "indexSize" : 109345824,
    "fileSize" : 4226809856,
    "nsSizeMB" : 16,
    "dataFileVersion" : {
        "major" : 4,
        "minor" : 6
    },
    "extentFreeList" : {
        "num" : 11,
        "totalSize" : 35610624
    },
    "ok" : 1
}

初步怀疑是因为某些不当操作导致mongodb存储碎片过多造成速度变慢。

解决

查文档,mongo 1.9+可以使用compact命令在线不停机进行collection压缩。

在生产服务器上执行如下命令:

> db.getCollectionNames().forEach(function (collectionName) {
...     print('Compacting: ' + collectionName);
...     db.runCommand({ compact: collectionName });
... });

对当前db(已经use)里面的所有collections进行遍历并压缩。

压缩刚刚完成时,extentFreeList反而增大,查询变得更慢:

> db.stats()
{
    "db" : "web",
    "collections" : 37,
    "objects" : 697658,
    "avgObjSize" : 2777.5333358178364,
    "dataSize" : 1937768352,
    "storageSize" : 2088890368,
    "numExtents" : 162,
    "indexes" : 55,
    "indexSize" : 105756560,
    "fileSize" : 6373244928,
    "nsSizeMB" : 16,
    "dataFileVersion" : {
        "major" : 4,
        "minor" : 6
    },
    "extentFreeList" : {
        "num" : 96,
        "totalSize" : 2151555072
    },
    "ok" : 1
}

> db.users.find({phoneNum:"18601163270"}).explain()
{
    "cursor" : "BasicCursor",
    "isMultiKey" : false,
    "n" : 1,
    "nscannedObjects" : 43941,
    "nscanned" : 43941,
    "nscannedObjectsAllPlans" : 43941,
    "nscannedAllPlans" : 43941,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 577,
    "nChunkSkips" : 0,
    "millis" : 8109,
    "server" : "MONGODB-2:27017",
    "filterSet" : false
}

此时,退出当前mongod连接。重新连接mongo,extentFreeList变为0,并且查询millis=0(没有use web)。

先use web:

> use web
switched to db web
> db.users.find({phoneNum:"18601163270"}).explain()
{
    "cursor" : "BasicCursor",
    "isMultiKey" : false,
    "n" : 1,
    "nscannedObjects" : 43941,
    "nscanned" : 43941,
    "nscannedObjectsAllPlans" : 43941,
    "nscannedAllPlans" : 43941,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 343,
    "nChunkSkips" : 0,
    "millis" : 682,
    "server" : "MONGODB-2:27017",
    "filterSet" : false
}
> db.stats()
{
    "db" : "web",
    "collections" : 37,
    "objects" : 697659,
    "avgObjSize" : 2777.529698606339,
    "dataSize" : 1937768592,
    "storageSize" : 2088890368,
    "numExtents" : 162,
    "indexes" : 55,
    "indexSize" : 105756560,
    "fileSize" : 6373244928,
    "nsSizeMB" : 16,
    "dataFileVersion" : {
        "major" : 4,
        "minor" : 6
    },
    "extentFreeList" : {
        "num" : 96,
        "totalSize" : 2151555072
    },
    "ok" : 1
}

repairDatabase,也无效:

> db.repairDatabase()
{ "ok" : 1 }
> db.users.find({phoneNum:"18601163270"}).explain()
{
    "cursor" : "BasicCursor",
    "isMultiKey" : false,
    "n" : 1,
    "nscannedObjects" : 43941,
    "nscanned" : 43941,
    "nscannedObjectsAllPlans" : 43941,
    "nscannedAllPlans" : 43941,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 343,
    "nChunkSkips" : 0,
    "millis" : 671,
    "server" : "MONGODB-2:27017",
    "filterSet" : false
}

重启mongod服务。发现extentFreeList变小了,查询速度变快了:

> use web
switched to db web
> db.stats()
{
    "db" : "web",
    "collections" : 37,
    "objects" : 697659,
    "avgObjSize" : 2777.5309140998684,
    "dataSize" : 1937769440,
    "storageSize" : 2136621056,
    "numExtents" : 164,
    "indexes" : 55,
    "indexSize" : 105756560,
    "fileSize" : 4226809856,
    "nsSizeMB" : 16,
    "dataFileVersion" : {
        "major" : 4,
        "minor" : 6
    },
    "extentFreeList" : {
        "num" : 1,
        "totalSize" : 131072
    },
    "ok" : 1
}
> db.users.find({phoneNum:"18601163270"}).explain()
{
    "cursor" : "BasicCursor",
    "isMultiKey" : false,
    "n" : 1,
    "nscannedObjects" : 43941,
    "nscanned" : 43941,
    "nscannedObjectsAllPlans" : 43941,
    "nscannedAllPlans" : 43941,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 343,
    "nChunkSkips" : 0,
    "millis" : 31,
    "server" : "MONGODB-2:27017",
    "filterSet" : false
}

通过上面的一步步验证,问题得到了解决,但是如果只是重启mondodb,不知道问题是否可以得到解决,还有待验证。




最后编辑:
作者:tshare365
这个作者貌似有点懒,什么都没有留下。
捐 赠您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请狠狠点击

留下一个回复