0

通知用のストレージとして mongo db を部分的に使用する製品があります。ほぼ 2 か月間ライブですが、深刻なパフォーマンスの問題に直面しています。通知の問題のために設計した構造を紹介しましょう。

3 つの基本的なコレクションがあります。

notification_item, notification_subscriptions and notification_actions

システム上のすべてのユーザー作成データは、notification_itemを含むownerを作成しcreation_dateます。meta data

次に、データの所有者 (最初のステップで作成されます) は、コレクション notification_itemを通じてそのデータを購読します。(コレクションへの参照) と誰が購読したかで構成されます。notification_subscriptionnotification_subscriptionnotification_item's object idnotification_itemuser_id

最後はnotification_actionコレクションです。任意の通知項目に対する任意のアクションが挿入されるのは簡単です。それは構造でありnotification_item's object idcreation_dateそしてother meta data。通知アクションを作成するすべてのユーザーは、その通知アイテムをサブスクライブして、さらに通知をリッスンします。

とにかく、これまでのドキュメントのサイズは count です。

notification_items = 4348

notification_subscription = 11324

notification_action = 12226

ほとんどの notification_items クエリを購読しているユーザーの notification_action でクエリを実行すると、問題が発生します。クエリの実行が非常に遅いです。

の数のユーザーがサブスクライブしたとしましょう

notification_items = 778

ローカルで 15 秒間実行され、そのユーザーのすべてのアクションが取得されます。これがクエリです(phpですが、同じ結果であるjavascriptでテストしました);

public function getNewNotificationsByUserId($id){

    $loggingImpl = new LoggingImpl();

    $subsColl = "notification_sub";

    $cursor = $this->mongoDb->db->$subsColl->find(array("user_id" => "$id"));

    $subs = array();

    while($doc = $cursor->getNext()){

        $subs[] = array("not_item._id" => $doc['not_item'],'creation_date' => array('$gte' => $doc['creation_date']));  
    }

    $actions = array();

    if(empty($subs)){
        return $actions;
    }


    $actionColl = NotificationAction::COLL;


    $query = array('$or' => $subs, 'owner.id' => array('$ne' => "$id" ));

    $d1 = microtime(true);
    $cursor = $this->mongoDb->db->$actionColl->find($query)->sort(array('creation_date' => -1));

    while($doc = $cursor->getNext()){

        $actions[] = $doc;
    }
    $d2 = microtime(true);
    $loggingImpl->logDebug("notification data:".($d2-$d1));

    return $actions;
}

インデックスオン後creation_datenotification_actionパフォーマンスが2番目に向上しました0.97

しかし、それはまだ製品には悪いです。データベースは適度にいっぱいではありません。今後の負担が心配です。何を指示してるんですか?簡単なトリックで調整できますか?それとも、構造を再設計する必要がありますか?

編集:これはクエリログです。

> db.system.profile.find().limit(10).sort( { ts : -1 } ).pretty()
{
    "op" : "query",
    "ns" : "splive.notification_action",
    "query" : {
        "$query" : {
            "$or" : [
                {
                    "not_item._id" : ObjectId("51991be7a46da17941000000"),
                    "creation_date" : {
                        "$gte" : ISODate("2013-08-08T14:05:54.170Z")
                    }
                }, ... (***778 item***)
             ],
            "owner.id" : {
                "$ne" : "1"
            }
        },
        "$orderby" : {
            "creation_date" : -1
        }
    },
    "ntoreturn" : 0,
    "ntoskip" : 0,
    "nscanned" : 12226,
    "keyUpdates" : 0,
    "numYield" : 1,
    "lockStats" : {
        "timeLockedMicros" : {
            "r" : NumberLong(912990),
            "w" : NumberLong(0)
        },
        "timeAcquiringMicros" : {
            "r" : NumberLong(10239),
            "w" : NumberLong(8)
        }
    },
    "nreturned" : 0,
    "responseLength" : 20,
    "millis" : 902,
    "ts" : ISODate("2013-08-08T15:58:39.758Z"),
    "client" : "127.0.0.1",
    "allUsers" : [ ],
    "user" : ""
}
4

0 に答える 0