limit() 和 sort() 顺序 pymongo 和 mongodb

新手上路,请多包涵

尽管阅读了人们的回答,指出排序是首先完成的,但证据表明限制是在排序之前完成的,这是不同的。有没有办法总是先强制排序?

 views = mongo.db.view_logging.find().sort([('count', 1)]).limit(10)

无论我使用 .sort().limit() 还是 .limit().sort() ,限制优先。我想知道这是否与 pymongo

原文由 disruptive 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 690
2 个回答

根据 文档无论您的命令链中哪个先行, sort() 将始终在 limit() 之前应用。

您还可以研究查询的 .explain() 结果并查看执行阶段 - 您会发现排序输入阶段检查所有过滤的(在您的情况下是集合中的所有文档)然后限制被申请;被应用。


让我们来看一个例子。

假设有一个 foo 数据库和一个 test 包含 6 个文档的集合:

 >>> col = db.foo.test
>>> for doc in col.find():
...     print(doc)
{'time': '2016-03-28 12:12:00', '_id': ObjectId('56f9716ce4b05e6b92be87f2'), 'value': 90}
{'time': '2016-03-28 12:13:00', '_id': ObjectId('56f971a3e4b05e6b92be87fc'), 'value': 82}
{'time': '2016-03-28 12:14:00', '_id': ObjectId('56f971afe4b05e6b92be87fd'), 'value': 75}
{'time': '2016-03-28 12:15:00', '_id': ObjectId('56f971b7e4b05e6b92be87ff'), 'value': 72}
{'time': '2016-03-28 12:16:00', '_id': ObjectId('56f971c0e4b05e6b92be8803'), 'value': 81}
{'time': '2016-03-28 12:17:00', '_id': ObjectId('56f971c8e4b05e6b92be8806'), 'value': 90}

现在,让我们以不同的顺序执行查询 sort()limit() 并检查结果和解释计划。

排序然后限制:

 >>> from pprint import pprint
>>> cursor = col.find().sort([('time', 1)]).limit(3)
>>> sort_limit_plan = cursor.explain()
>>> pprint(sort_limit_plan)
{u'executionStats': {u'allPlansExecution': [],
                     u'executionStages': {u'advanced': 3,
                                          u'executionTimeMillisEstimate': 0,
                                          u'inputStage': {u'advanced': 6,
                                                          u'direction': u'forward',
                                                          u'docsExamined': 6,
                                                          u'executionTimeMillisEstimate': 0,
                                                          u'filter': {u'$and': []},
                                                          u'invalidates': 0,
                                                          u'isEOF': 1,
                                                          u'nReturned': 6,
                                                          u'needFetch': 0,
                                                          u'needTime': 1,
                                                          u'restoreState': 0,
                                                          u'saveState': 0,
                                                          u'stage': u'COLLSCAN',
                                                          u'works': 8},
                                          u'invalidates': 0,
                                          u'isEOF': 1,
                                          u'limitAmount': 3,
                                          u'memLimit': 33554432,
                                          u'memUsage': 213,
                                          u'nReturned': 3,
                                          u'needFetch': 0,
                                          u'needTime': 8,
                                          u'restoreState': 0,
                                          u'saveState': 0,
                                          u'sortPattern': {u'time': 1},
                                          u'stage': u'SORT',
                                          u'works': 13},
                     u'executionSuccess': True,
                     u'executionTimeMillis': 0,
                     u'nReturned': 3,
                     u'totalDocsExamined': 6,
                     u'totalKeysExamined': 0},
 u'queryPlanner': {u'indexFilterSet': False,
                   u'namespace': u'foo.test',
                   u'parsedQuery': {u'$and': []},
                   u'plannerVersion': 1,
                   u'rejectedPlans': [],
                   u'winningPlan': {u'inputStage': {u'direction': u'forward',
                                                    u'filter': {u'$and': []},
                                                    u'stage': u'COLLSCAN'},
                                    u'limitAmount': 3,
                                    u'sortPattern': {u'time': 1},
                                    u'stage': u'SORT'}},
 u'serverInfo': {u'gitVersion': u'6ce7cbe8c6b899552dadd907604559806aa2e9bd',
                 u'host': u'h008742.mongolab.com',
                 u'port': 53439,
                 u'version': u'3.0.7'}}

限制然后排序:

 >>> cursor = col.find().limit(3).sort([('time', 1)])
>>> limit_sort_plan = cursor.explain()
>>> pprint(limit_sort_plan)
{u'executionStats': {u'allPlansExecution': [],
                     u'executionStages': {u'advanced': 3,
                                          u'executionTimeMillisEstimate': 0,
                                          u'inputStage': {u'advanced': 6,
                                                          u'direction': u'forward',
                                                          u'docsExamined': 6,
                                                          u'executionTimeMillisEstimate': 0,
                                                          u'filter': {u'$and': []},
                                                          u'invalidates': 0,
                                                          u'isEOF': 1,
                                                          u'nReturned': 6,
                                                          u'needFetch': 0,
                                                          u'needTime': 1,
                                                          u'restoreState': 0,
                                                          u'saveState': 0,
                                                          u'stage': u'COLLSCAN',
                                                          u'works': 8},
                                          u'invalidates': 0,
                                          u'isEOF': 1,
                                          u'limitAmount': 3,
                                          u'memLimit': 33554432,
                                          u'memUsage': 213,
                                          u'nReturned': 3,
                                          u'needFetch': 0,
                                          u'needTime': 8,
                                          u'restoreState': 0,
                                          u'saveState': 0,
                                          u'sortPattern': {u'time': 1},
                                          u'stage': u'SORT',
                                          u'works': 13},
                     u'executionSuccess': True,
                     u'executionTimeMillis': 0,
                     u'nReturned': 3,
                     u'totalDocsExamined': 6,
                     u'totalKeysExamined': 0},
 u'queryPlanner': {u'indexFilterSet': False,
                   u'namespace': u'foo.test',
                   u'parsedQuery': {u'$and': []},
                   u'plannerVersion': 1,
                   u'rejectedPlans': [],
                   u'winningPlan': {u'inputStage': {u'direction': u'forward',
                                                    u'filter': {u'$and': []},
                                                    u'stage': u'COLLSCAN'},
                                    u'limitAmount': 3,
                                    u'sortPattern': {u'time': 1},
                                    u'stage': u'SORT'}},
 u'serverInfo': {u'gitVersion': u'6ce7cbe8c6b899552dadd907604559806aa2e9bd',
                 u'host': u'h008742.mongolab.com',
                 u'port': 53439,
                 u'version': u'3.0.7'}}

如您所见,在这两种情况下,首先应用排序并影响所有 6 个文档,然后 limit 将结果限制为 3 个。

而且, 执行计划完全相同

 >>> from copy import deepcopy  # just in case
>>> cursor = col.find().sort([('time', 1)]).limit(3)
>>> sort_limit_plan = deepcopy(cursor.explain())
>>> cursor = col.find().limit(3).sort([('time', 1)])
>>> limit_sort_plan = deepcopy(cursor.explain())
>>> sort_limit_plan == limit_sort_plan
True

另见:

原文由 alecxe 发布,翻译遵循 CC BY-SA 3.0 许可协议

mongodb 文档指出 skip() 方法控制结果集的起点,然后是 sort() 并以 limit() 方法结束

这与您的代码顺序无关。原因是 mongo 获取了查询的所有方法,然后它以准确的顺序对 skip-sort-limit 方法进行排序,然后运行查询。

原文由 jquijano 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题