当实际查询仅花费几毫秒时,为什么提取MongoDB结果会变慢?

时间:2013-01-07 06:45:01

标签: mongodb optimization doctrine doctrine-odm

我正在使用Doctrine MongoDB ODM从远程MongoDB数据库中获取少量文档。

我确认查询只花了1毫秒才找到大约12个匹配的文档。 (即'millis':1来自解释输出)。但迭代结果需要大约250毫秒。

当我尝试以下选项的组合时,我无法获得任何性能提升

  • 选择( '姓名')
  • 水合物(假)
  • eagerCursor(真)
  • 限制(1)

如何最大程度地减少此延迟?


更新:使用示例代码进行更多说明

$qb = $dm->createQueryBuilder('Books');
$books = $qb->select('name')
            ->field('userId')->equals(123)
            ->field('status')->equals('active')
            ->eagerCursor(true)  // Fetch all data at once
            ->getQuery()
            ->execute();

/**
 * Due to using Eager Cursor, the database connection should be closed and
 * all data should be in memory now.
 */

// POINT A
foreach($books as $book) {
    // I do nothing here. Just looping through the results.
}
// POINT B.

/**
 * From POINT A to POINT B takes roughly 250ms when the query had 12 matching docs.
 * And this doesn't seem to be affected much by the number of records matched.
 * As the data is already in the memory, I expected this to be done in range of 
 * 5~10ms, not 250ms.
 *
 * Am I misunderstanding the meaning of Eager Cursor?
 */

2 个答案:

答案 0 :(得分:0)

这里有两个感兴趣的区间:一个是从代码的开头到A点;第二个是从A点到B点。由.explain()测量的是前者;你测量的是后者。

特别是,一旦将BSON文档传输到客户端(您的PHP程序),它们仍然需要反序列化并转换为PHP对象。如果您正在使用Doctrine,那么还必须执行其他处理。

您看到的时间是反序列化过程的时间。文件有多大?必须反序列化文档的整个内容:如果这些内容很大或很复杂(深层嵌套,许多数组等),那么这可能需要一些时间。

只需获取所需的字段,即可缩短反序列化时间。如果您在查询中添加 - > select('_ id'),则循环时间应该快得多。

答案 1 :(得分:0)

好吧,看起来我误解了Eager Cursor的含义。

http://docs.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/reference/eager-cursors.html 本文档建议在调用 execute()时,将所有结果检索到内存中。但那不太准确。相反,我发现第一次访问EasgerCursor时会记录这些记录。

在EagerCursor的 initialize()函数中,检索普通Mongo Cursor的实例,并在执行其他一些函数后最终传递到 iterator_to_array()函数。我很确定这是Mongo Driver真正完成获取记录的工作。

在我的情况下,这发生在 foreach 循环中。因此,在A点和B点之间观察到延迟。为了证实这一点,我尝试了MongoClient实现,发现实现之间的总体时间非常接近。

感谢大家的帮助。