mongo + PHP的性能问题与分页,不同的值

时间:2011-08-30 00:16:40

标签: php performance mongodb filtering distinct

我有一个mongodb集合包含许多有很多字段的书籍。与我的问题相关的一些关键字段是:

{
book_id : 1, 
book_title :"Hackers & Painters", 
category_id : "12",
related_topics : [ {topic_id : "8", topic_name : "Computers"},
                   {topic_id : "11", topic_name : "IT"}
                 ]
...
... (at least 20 fields more)
...
}

我们在搜索页面上有一个用于过滤结果的表单(包含许多输入/选择框)。当然还有分页。通过过滤后的结果,我们会在页面上显示所有类别。对于每个类别,该类别中的结果数量也会显示在页面上。

我们尝试使用MongoDB而不是PostgreSQL。因为性能和速度是我们这个过程的主要关注点。

现在的问题是:

我可以通过向所有过滤器参数提供“查找”功能来轻松过滤结果。这很酷。我可以使用跳过和限制函数对结果进行分页:

$data = $lib_collection->find($filter_params, array())->skip(20)->limit(20);

但是我必须收集在分页发生之前为每个category_id和topic_id找到的结果数。而且我不想“预测”所有结果,收集类别并使用PHP管理分页,因为过滤后的数据通常包含近200,000个结果。

问题1:我在PHP手册中找到了mongodb :: command()函数,带有“distinct”示例。我认为我通过这种方法获得了不同的价值观。但是命令功能不接受条件参数(用于过滤)。在询问不同的值时,我不知道如何应用相同的过滤器参数。

问题2:即使有一种方法可以使用mongodb :: command函数发送过滤器参数,这个函数也将是该过程中的另一个查询,并且大约需要相同的时间(可能更多)以前的查询我认为。这将是另一个速度惩罚。

问题3:为了获得具有多个结果的不同topic_ids将是另一个查询,另一个速度惩罚:(

我是使用MongoDB的新手。也许我从错误的角度看待问题。你能帮助我解决问题并就最快的方式发表意见:

  • 过滤结果
  • 分页
  • 找到结果数量的不同值

来自大型数据集。

2 个答案:

答案 0 :(得分:3)

因此,过滤结果和分页的简便方法如下:

$cursor = $lib_collection->find($filter_params, array())
$count = $cursor->count();
$data = $cursor->skip(20)->limit(20);

但是,这种方法可能效率不高。如果查询未编制索引的字段,服务器“count()”的唯一方法是加载每个文档并进行检查。如果您执行skip()limit()而没有sort(),那么服务器只需要查找前20个匹配的文档,这样做的工作要少得多。

每个类别的结果数将变得更加困难。

如果数据不经常更改,您可能希望使用常规map / reduce作业预先计算这些值。否则,您必须运行一系列distinct()命令或内联map / reduce。这两者通常都不用于临时查询。

唯一的其他选择基本上是加载所有搜索结果,然后依靠网络服务器(而不是数据库)。显然,这也是效率低下的。

获得所有这些功能需要进行一些规划和权衡。

答案 1 :(得分:3)

分页

小心对大型数据集进行分页。请记住,skip()take() - 无论您是否使用索引都无关紧要 - 必须执行扫描。因此,跳过很远很慢。

可以这样想:数据库有一个索引(B-Tree)可以相互比较值:它可以快速告诉你某些东西是大于还是小于给定的x。因此,均衡树中的搜索时间是对数的。对于基于计数的索引,这是 true:B-Tree无法快速告诉您第15.000个元素是什么:它必须遍历并枚举整个树。

来自documentation

  

分页费用

     

不幸的是,跳过可能(非常)昂贵且需要   服务器从集合的开头或索引走到get   到它可以开始返回页面之前的偏移/跳过位置   数据(限制)。随着页码增加,跳过将变慢   更大的集合,更多的CPU密集,可能IO绑定。

     

基于范围的分页提供了更好的索引使用但不允许   您可以轻松跳转到特定页面。

确保您确实需要此功能:通常,没有人关心42436的结果。请注意,大多数大型网站从不让您分页很远,更不用说显示确切的总数。关于这个话题有一个很棒的网站,但是我没有手边的地址,也没有找到它的名字。

不同的主题计数

我相信你可能使用大锤作为漂浮装置。看看您的数据:related_topics。由于对象关系映射,我个人讨厌 RDBMS,但这个似乎是关系数据库的完美用例。

如果您的文档非常大,性能是一个问题并且您像我一样讨厌ORM,您可能需要考虑使用两个 MongoDB和您选择的RDBMS:让MongoDB获取结果和RDBMS聚合给定类别的最佳匹配。你甚至可以并行运行查询!当然,需要在两个数据库上写入对DB的更改。