3

だから、私は今phpフレームワークリチウムを試しています、そしてそれは本当に良いフレームワークのようです、そしてすべて私はわずかな問題を抱えています。6k以上のドキュメントのみを含むコレクションで実行するクエリは、phpからは驚くほど遅いですが、ターミナルから実行すると非常に高速になります。

コレクション内の1つのドキュメントは次のようになります。

{
    "_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"
}

今月のすべてのエピソードを取得したいと思います。したがって、ターミナルでは(私は偽の値を使用し、1か月以上使用しています)、次のクエリを使用します。

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

そして、ワム、それは非常に速く進みます。クエリで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とlithium内でクエリを使用すると、時間がかかります。

$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())。これにより、生の配列または実際のデータベースカーソルのいずれかを取得できます。手動で繰り返すことができます。

もう1つのオプションは、ストリーミングの反復を実装するまで待つことです。これにより、メモリの問題が解決されます。:-)

于 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 に答える