3

所以,我现在一直在尝试 php 框架锂,它似乎是一个非常好的框架,但我有一个小问题。我在一个只有 6k+ 文档的集合上运行的查询从 php 运行速度非常慢,但当我从终端运行它时却非常快。

集合中的一个文档可能如下所示:

{
    "_id" : ObjectId("504c9a3b6070d8b7ea61938e"),
    "startDate" : "Jan 2011",
    "episodes" : [
        {
            "title" : "Series 1, Episode 1",
            "airdate" : ISODate("2011-01-20T00:00:00Z"),
            "epnum" : "1",
            "prodnum" : null,
            "seasonnum" : "01",
            "link" : "http://www.tvrage.com/10_OClock_Live/episodes/1065007783"
        },
        {and maybe 20 more},
    ],
    "runTime" : "60 min",
    "endDate" : "Apr 2012",
    "network" : "Channel 4",
    "numberOfEpisodes" : "25 eps",
    "title" : "10 O'Clock Live",
    "directory" : "10OClockLive",
    "country" : "UK",
    "tvrage" : "27363"
}

我想获取本月存在的所有剧集。所以在终端(我使用假值和一个多月)我使用以下查询:

db.series.find({'episodes.airdate': {$gt: ISODate('2012-09-07 00:00:00'), $lt: ISODate('2012-11-01')}})

和wham,它只是非常快。即使我对查询执行了 explain() ,它也会告诉我它很快:

{
    "cursor" : "BtreeCursor episodes.airdate_1",
    "isMultiKey" : true,
    "n" : 382,
    "nscannedObjects" : 1620,
    "nscanned" : 1620,
    "nscannedObjectsAllPlans" : 1620,
    "nscannedAllPlans" : 1620,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 0,
    "nChunkSkips" : 0,
    **"millis" : 181**,
    "indexBounds" : {
        "episodes.airdate" : [
            [
                ISODate("2012-09-07T00:00:00Z"),
                ISODate("292278995-01--2147483647T07:12:56.808Z")
            ]
        ]
    },
    "server" : "example:27017"
}

但是当我在 php 和锂中使用查询时,伙计,它需要很长时间:

$series = Series::find('all', array(
                'fields' => array('title', 'episodes.title', 'episodes.airdate'),
                'conditions' => array('episodes.airdate' => array('$gt' => new MongoDate(strtotime(date('Y-m-01'))), '$lt' =>  new MongoDate(strtotime(date('Y-m-t')))))
            ));

如果我什至尝试循环遍历它,那么在超过30 秒的执行时间后情况会更糟。尽管如此,我认为我有内存泄漏,因为我不得不添加它ini_set('memory_limit', '-1');而没有获得“最大使用量”或其他任何东西。

谁能给我一个关于为什么会发生这种情况的答案?有什么办法可以提高查询速度?我不知道为什么它这么慢,如果有人能指出我正确的方向,我会非常高兴。

4

3 回答 3

5

问题是 Lithium 将所有数据打包在对象中,对于大型查询来说,这可能会占用大量内存,因此速度很慢。如果您不需要针对该特定查询的任何 ActiveRecord 功能,则可以传递一个选项,您可以将find()其传递给MongoDb::read()(因此请检查文档MongoDb::read()),该选项允许您取回原始数组或实际的数据库游标可以手动迭代。

另一种选择是等到我实现流式迭代,这将解决内存问题。:-)

于 2012-10-09T15:27:04.427 回答
1

我不确定为什么这对你来说很慢。我在这里有一个要点,其中一个类将记录从锂发出的插入、读取和更新 mongo 命令。您可能可以添加某种类型的计时器来获取每个查询的长度。然后你至少可以知道问题是在等待 mongo 还是代码的其他部分。

这是一些用于迭代一段DocumentSet时间的代码,丢弃从MongoCursor循环中检索到的每个文档。

$docs = SomeModel::all();
while ($docs->valid()) {
    $key = $docs->key();
    $doc = $docs->current();
    unset($docs[$key]);
    $docs->rewind();

    if (!$docs->valid()) {
        $docs->next();
    }

    // ... do stuff with $doc here ...
}
于 2012-10-08T05:41:07.093 回答
0

我刚刚解决了一个页面加载时间超过 65 秒的问题。原来这个特定用户的用户记录有一个包含 152 条记录的数组,每个数组项都非常大,所以这个帐户可能超过了 mongodb 记录的 65,000 个字符的限制。当我从用户帐户中删除大数组时,页面突然以 4.5 秒加载。

问题是 - 正在加载的页面上的内容与此用户记录无关,因此我们正在处理该内容的查询以尝试加快速度。然后我们发现该错误与所有这些完全无关,并且是由于另一个问题造成的。

因此,请确保您的记录不要太大。

于 2013-10-17T19:34:24.857 回答