Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
mongodb中数以吨计的记录的慢速分页_Mongodb - Fatal编程技术网

mongodb中数以吨计的记录的慢速分页

mongodb中数以吨计的记录的慢速分页,mongodb,Mongodb,我在Mongo的一个收藏中拥有超过30万张唱片 当我运行这个非常简单的查询时: db.myCollection.find().limit(5); 只需要几毫秒 但当我在查询中使用skip时: db.myCollection.find().skip(200000).limit(5) 它不会返回任何东西。。。它运行数分钟,但不返回任何内容 如何让它变得更好?来自MongoDB: 寻呼成本 不幸的是,skip可能(非常)昂贵,需要服务器从集合或索引的开始走到offset/skip位置,然后才能开始

我在Mongo的一个收藏中拥有超过30万张唱片

当我运行这个非常简单的查询时:

db.myCollection.find().limit(5);
只需要几毫秒

但当我在查询中使用skip时:

db.myCollection.find().skip(200000).limit(5)
它不会返回任何东西。。。它运行数分钟,但不返回任何内容

如何让它变得更好?

来自MongoDB:

寻呼成本

不幸的是,skip可能(非常)昂贵,需要服务器从集合或索引的开始走到offset/skip位置,然后才能开始返回数据页(limit)。随着页数的增加,skip将变得更慢,cpu密集度更高,并且可能受IO限制,集合更大

基于范围的分页可以更好地使用索引,但不允许轻松跳转到特定页面


你必须问自己一个问题:你多久需要40000页?另见文章

解决此问题的一种方法是,如果您有大量文档,并且您正在按排序顺序显示它们(如果您不这样做,我不确定
skip
有多大用处),则使用正在排序的键选择下一页的结果

所以如果你从

db.myCollection.find().limit(100).sort({created_date:true});
然后将光标返回的最后一个文档的创建日期提取到变量
max\u created\u date\u中,从\u last\u result
,您可以通过更高效的查询(假设您在
created\u date
上有索引)获得下一页


我发现将这两个概念结合在一起(跳过+限制和查找+限制)非常有效。skip+limit的问题是,当您有大量文档(尤其是较大的文档)时,性能较差。find+limit的问题是您不能跳转到任意页面。我希望能够不按顺序分页

我采取的步骤是:

  • 根据您希望对文档进行排序的方式创建索引,或者只使用默认的_id索引(这就是我使用的)
  • 了解起始值、页面大小和要跳转到的页面
  • 项目+跳过+限制应从中开始的值
  • 查找并限制页面的结果
  • 如果我想得到第5432页共16条记录(javascript),大致如下所示:


    这是因为即使跳过数百万条记录(这就是我正在做的),对预测索引的跳过也非常快。如果运行
    explain(“executionStats”)
    ,它仍然有大量的
    totalDocsExamined
    ,但由于在索引上的投影,它的速度非常快(基本上,从不检查数据块)。然后,有了当前页面开始的值,您可以很快获取下一页。

    我连接了两个答案

    问题是当您使用skip and limit时,没有排序,它只是按照表的顺序分页,与您将数据写入表的顺序相同,所以引擎需要创建第一个临时索引。使用ready _idindex:)比使用像这样的大型表更快,您需要使用sort by _id

    db.myCollection.find().skip(4000000).limit(1).sort({ "_id": 1 });
    
    在PHP中,它将是

    $manager = new \MongoDB\Driver\Manager("mongodb://localhost:27017", []);
    $options = [
                'sort' => array('_id' => 1),
                'limit' => $limit, 
                'skip' => $skip,
    
            ];
    $where = [];
    $query = new \MongoDB\Driver\Query($where, $options );
    $get = $manager->executeQuery("namedb.namecollection", $query);
    

    这看起来真的很好。为什么我看不到更多的人提出这个建议呢?嗯,它的局限性在于你一次只能向前或向后浏览一页,而不是跳到一个特定的页面,但是对于这个有限的用例,我认为它工作得很好。我发现这个答案使用了与上面类似的机制:它可能会有帮助。这种方法应该谨慎使用,因为如果结果具有与上次结果相同的
    created\u date
    ,则会导致忽略结果。查看哪个提供了在
    \u id
    和时间戳上使用复合索引的解决方案。这是一种合理的方法,但并不完美,因为您无法跳转页面。我看到一个限制,如果记录是按名称排序的,例如:
    product.name
    。我真的很惊讶看到MangoDB中没有真正支持
    skip
    ,这对我来说是一个破坏者。它是一个索引,应该是即时的,最糟糕的是,如果你有100万个文档,跳过1000万个,仍然需要一分钟,这很难理解,mongo在任何时候都不知道一个集合有多少文档吗?但我的主要观点是,为什么获取第n个文档很慢?这不是我们首先使用数据库的原因吗?@MartijnScheffer best comment Every当你进行裸体查找时(可爱吧),它实际上根本不使用索引(因为你没有任何查询/筛选功能)。。。因此,它正在一路上对每个项目(文档)进行完整的COLSCAN检查。您可以尝试此技巧,至少使用默认ID索引。。。db.myCollection.find({''u id':{'$gt':'''}).skip(20000).limit(5)类似这样的内容至少会删除大型文档扫描,坚持索引扫描。当使用skip/limit时,为了坚持索引扫描,您必须使用索引中完全包含的过滤器,否则它必须转到文档来解决问题。您也可以不使用_id进行查询,而只按_id排序以触发索引使用。db.myCollection.find().skip(20000).sort({“\u id”:1}).limit(5).explain(“executionStats”)我尝试了50万条记录,但投影增加了查询时间,@T先生,投影在MongoDB中不使用索引。
    db.myCollection.find().skip(4000000).limit(1).sort({ "_id": 1 });
    
    $manager = new \MongoDB\Driver\Manager("mongodb://localhost:27017", []);
    $options = [
                'sort' => array('_id' => 1),
                'limit' => $limit, 
                'skip' => $skip,
    
            ];
    $where = [];
    $query = new \MongoDB\Driver\Query($where, $options );
    $get = $manager->executeQuery("namedb.namecollection", $query);