4

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

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

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

  • 选择('名称')
  • 水合物(假)
  • 急切光标(真)
  • 限制(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?
 */
4

2 回答 2

0

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

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

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

您可以通过仅获取您需要的字段来减少反序列化时间。如果您在查询中添加 ->select('_id'),您的循环时间应该会快很多。

于 2013-01-08T00:59:13.643 回答
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 实现,发现实现之间的总体时间非常接近。

感谢大家的帮助。

于 2013-01-08T23:27:03.437 回答