[英]Very slow MongoDB count in big database
我有一个数据库,其中包含大量文档(数百万个)。 在这个数据库中,我(除其他外)具有字段_VIOLATIONTYPE(int)和_DURATION(int)。 现在,我想计算_VIOLATIONTYPE为15或更少和_DURATION为10或更少的文档的数量。 为此,我执行以下Python脚本:
#!/usr/bin/env python
import pymongo
import timeit
client = pymongo.MongoClient('localhost', 27017)
database = client['bgp_route_leaks']
collection = database['valleys']
collection.ensure_index('_VIOLATIONTYPE', unique=False)
collection.ensure_index('_DURATION', unique=False)
start = timeit.default_timer()
cursor = collection.find({'$and': [{'_VIOLATIONTYPE': {'$lt': 16}}, {'_DURATION': {'$lt': 10}}]}, {'_DURATION': 1, '_id': 0})
print('Explain: {}'.format(cursor.explain()))
print('Count: {}'.format(cursor.count()))
print('Time: {}'.format(timeit.default_timer() - start))
打印输出:
Explain: {u'nYields': 4, u'nscannedAllPlans': 6244545, u'allPlans': [{u'cursor': u'BtreeCursor _VIOLATIONTYPE_1', u'indexBounds': {u'_VIOLATIONTYPE': [[-1.7976931348623157e+308, 16]]}, u'nscannedObjects': 124, u'nscanned': 124, u'n': 34}, {u'cursor': u'BtreeCursor _DURATION_1', u'indexBounds': {u'_DURATION': [[-1.7976931348623157e+308, 10]]}, u'nscannedObjects': 6244298, u'nscanned': 6244298, u'n': 5678070}, {u'cursor': u'BasicCursor', u'indexBounds': {}, u'nscannedObjects': 123, u'nscanned': 123, u'n': 36}], u'millis': 30815, u'nChunkSkips': 0, u'server': u'area51:27017', u'n': 5678107, u'cursor': u'BtreeCursor _DURATION_1', u'scanAndOrder': False, u'indexBounds': {u'_DURATION': [[-1.7976931348623157e+308, 10]]}, u'nscannedObjectsAllPlans': 6244545, u'isMultiKey': False, u'indexOnly': True, u'nscanned': 6244298, u'nscannedObjects': 6244298}
Count: 5678107
Time: 52.4030768871
运行此命令时,我还在另一个窗口中执行了db.currentOp(),该窗口返回了
{
"inprog" : [
{
"opid" : 15,
"active" : true,
"secs_running" : 4,
"op" : "query",
"ns" : "bgp_route_leaks.valleys",
"query" : {
"$query" : {
"$and" : [
{
"_VIOLATIONTYPE" : {
"$lt" : 16
}
},
{
"_DURATION" : {
"$lt" : 10
}
}
]
},
"$explain" : true
},
"client" : "127.0.0.1:46819",
"desc" : "conn1",
"threadId" : "0x7fd69b31c700",
"connectionId" : 1,
"locks" : {
"^" : "r",
"^bgp_route_leaks" : "R"
},
"waitingForLock" : false,
"numYields" : 5,
"lockStats" : {
"timeLockedMicros" : {
"r" : NumberLong(8816104),
"w" : NumberLong(0)
},
"timeAcquiringMicros" : {
"r" : NumberLong(4408723),
"w" : NumberLong(0)
}
}
}
]
}
现在,我读到慢速MongoDB查询的最常见来源是缺少索引。 但是,我已经确保_VIOLATIONTYPE和_DURATION都具有索引,并且说明告诉我u'indexOnly':是。 我还阅读了NUMA架构可能会减慢速度,并且我应该通过以下命令启动服务
sudo numactl --interleave=all /usr/bin/mongod --dbpath=/var/lib/mongodb
(/proc/sys/vm/zone_reclaim_mode is already set to 0)
我知道已经完成了,但是此计数仍然需要大约一分钟,而其他时间甚至需要更长的时间,因此我想知道如何做才能使查询更快。
运行
db.runCommand({compact: 'bgp_route_leaks'})
在mongo shell中也没有尝试过运气。
关于如何更快获得计数的任何建议?
MongoDB版本是2.4.9。
如果查看您的explain
输出,将会看到使用_VIOLATIONTYPE
的查询仅扫描124个对象,而使用_DURATION
的查询正在扫描6244545对象。
尽管MongoDB 2.6+可以使用索引交集 ,但是复合索引始终会更快。
您需要在这些字段上创建复合索引:
collection.create_index([("_VIOLATIONTYPE", ASCENDING),("_DURATION", ASCENDING)]);
编辑
在2.4版中,MongoDB的性能得到了显着提高( JIRA-1752 )。
另外,值得注意的是, explain
命令正在显示查询而不是计数命令的详细信息。
不幸的是,你不能使用explain
上的count
命令,但有一个售票开通针对这个问题。
要仅测量count
命令的性能,您可能应该从测试中删除explain
。 此外,您需要多次重复查询(100x,1000x ...),并取平均值以获得正确的值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.