2

mongodb には ->remove()->limit() はありません。そのため、タスクを解決するために小さなスクリプトを使用します。

<?php
$conn = new Mongo('127.0.0.1');
$db = $conn->experimentDB;
$experimentCollection = $db->experimentCollection;
foreach($ruleset AS $ruleset_item)
{
    $max_remove_loops=3;
    $max_limit_per_loop=1000;
    MongoCursor::$timeout = 1*60*1000;
    for($remove_loops=0;$remove_loops<$max_remove_loops;$remove_loops++)
    {
        if(!TEST)
            $cursor = $experimentCollection->find($ruleset_item)->limit($max_limit_per_loop);//->skip($remove_loops*$max_limit_per_loop);
        else
            $cursor = $experimentCollection->find($ruleset_item)->limit($max_limit_per_loop)->skip($remove_loops*$max_limit_per_loop);
        $items=0;
        foreach($cursor AS $cursor_item)
        {
            //print_r($cursor_item['_id']);
            print('.');
            if(!TEST)
                $experimentCollection->remove(array('_id' => $cursor_item['_id']));
            $items++;
        }
        if($items==0)
        {
            break;
            print(' that was the last one. DONE ');
        }
        //$cursor->reset();
    }
}
?>

これはで終わった

致命的なエラー:メッセージ「カーソルがタイムアウトしました (タイムアウト: 60000、残り時間: 0:0、ステータス: 0)」を含む例外「MongoCursorTimeoutException」がキャッチされませんでした

そのため、max_remove_loops と max_limit_per_loop でタスクを分割しようとし、max_limit_per_loop を 1min、1h、2h などに変更しました。

ただし、数百回の削除後にスクリプトがハングする別の問題があるようです。200 ~ 2000 の間の場合もあります。(print('.')でカウントされます)

これはランダムなバグのように見え、mongodb が管理しなければならない他のタスク、RAM、CPU 負荷に依存しています。

推測ですが、ループが削除のためにキューに入れられたのと同じカーソルをわずかな遅延でキャッチしている場合、削除のために問題が発生している可能性がありますか?

このスクリプトをフォールト トレラントに修正し、ハングする代わりに続行するにはどうすればよいですか?

4

1 に答える 1

1

ここでいくつかの改善を行うことができます。

まず、スクリプト_idは各ドキュメントのフィールドにのみアクセスします。したがって、_idプロジェクションにフィールドを明示的に含め、他のすべてのフィールドを暗黙的に除外することができます (つまり、MongoCollection::find()の 2 番目の引数)。これは、db.collection.find()のドキュメントにも記載されています。プロジェクションは、サーバーから返されるデータの量を制限するのに役立ちます。

さらに、このスクリプトで発行するクエリがインデックス化されていることを確認する必要があります。大きなスキップ オフセットを使用すると、MongoDB は最初にクエリを実行し、次に特定の数がスキップされて結果を返し始めるまで、結果を個別に調べます。インデックスが作成されていないクエリの場合、ディスク上のドキュメントをたどるプロセスが非常に遅くなる可能性があります。スキップのサイズによっては、インデックス付きクエリの場合でも遅くなる可能性があります。ページネーションに limit/skip を使用する代わりに、最後に見た値よりも大きい値または小さい値からピックアップする範囲クエリを利用することもできます。この方法に興味がある場合は、件名に関するいくつかのリンクを含むこの最近の回答を参照してください。

クエリをデバッグし、インデックスが作成されているかどうかを判断するには、MongoCursor::explain()を使用できます。その戻り値に関する追加のドキュメント (クエリがインデックス化されているかどうかを判断する方法など) は、cursor.explain()ドキュメントにあります。

最後に、何かを削除する前に、スクリプトをリファクタリングして、事前に削除する ID を収集することをお勧めします。ID が 12 バイトの ObjectId (PHP では MongoId オブジェクト) であると仮定すると、それらを配列に集めるのに問題はないはずです。これにより、クエリのすべての結果を制限なしで、またはビジネスをスキップすることができます。その後、一連の単一ドキュメントの削除を発行するか、$in演算子を使用して 1 つまたは複数の削除を発行して、一度に複数の ID に一致させることができます。

于 2013-08-20T20:13:51.710 に答える