1

非常に単純なクエリがあります。

db.users.update({"_id" : ObjectId("50710913a6427bfa2600000c") },{$inc: {"points" : 5}})

「ポイント」フィールドにインデックスがあります:

db.users.getIndices()
[
    {
        "v" : 1,
        "key" : {
            "_id" : 1
        },
        "ns" : "od.users",
        "name" : "_id_"
    },
    {
        "v" : 1,
        "key" : {
            "points" : 1
        },
        "ns" : "od.users",
        "name" : "points"
    },
    {
        "v" : 1,
        "key" : {
            "lastActivity" : -1
        },
        "ns" : "od.users",
        "name" : "lastActivity"
    }
]

わかりやすくするために、一部のインデックスは省略されています。

アイドル状態のデータベースと高速マシン (Amazon EC2 Hi I/O インスタンス) で MongoDB 2.2.3 でクエリを実行していますが、完了するまでに 1.7 秒以上かかります...

> db.system.profile.find({ns:"od.users"}).sort({$natural:-1}).limit(1).pretty()
{
    "ts" : ISODate("2013-02-13T20:44:52.858Z"),
    "op" : "update",
    "ns" : "od.users",
    "query" : {
        "_id" : ObjectId("50710913a6427bfa2600000c")
    },
    "updateobj" : {
        "$inc" : {
            "points" : 5
        }
    },
    "nscanned" : 1,
    "nupdated" : 1,
    "keyUpdates" : 1,
    "numYield" : 0,
    "lockStats" : {
        "timeLockedMicros" : {
            "r" : NumberLong(0),
            "w" : NumberLong(1747665)
        },
        "timeAcquiringMicros" : {
            "r" : NumberLong(0),
            "w" : NumberLong(5964)
        }
    },
    "millis" : 1747,
    "client" : "127.0.0.1",
    "user" : ""
}

インデックスを削除すると、クエリはすぐに完了します。

> db.system.profile.find({ns:"od.users"}).sort({$natural:-1}).limit(1).pretty()
{
    "ts" : ISODate("2013-02-13T20:47:03.032Z"),
    "op" : "update",
    "ns" : "od.users",
    "query" : {
        "_id" : ObjectId("50710913a6427bfa2600000c")
    },
    "updateobj" : {
        "$inc" : {
            "points" : 5
        }
    },
    "idhack" : true,
    "nupdated" : 1,
    "keyUpdates" : 0,
    "numYield" : 0,
    "lockStats" : {
        "timeLockedMicros" : {
            "r" : NumberLong(0),
            "w" : NumberLong(153)
        },
        "timeAcquiringMicros" : {
            "r" : NumberLong(0),
            "w" : NumberLong(5)
        }
    },
    "millis" : 0,
    "client" : "127.0.0.1",
    "user" : ""
}

コレクションには約 71K のドキュメントがあります。

> db.users.stats()
{
    "ns" : "od.users",
    "count" : 71236,
    "size" : 2389260264,
    "avgObjSize" : 33540.06771856926,
    "storageSize" : 3987849216,
    "numExtents" : 20,
    "nindexes" : 23,
    "lastExtentSize" : 1039589376,
    "paddingFactor" : 1.0000000002382583,
    "systemFlags" : 1,
    "userFlags" : 0,
    "totalIndexSize" : 1120676144,
    "indexSizes" : {
        "_id_" : 3343984,
        "email" : 4578560,
        "country_1" : 2649024,
        "wPopularity" : 3278576,
        "wRandom" : 2869776,
        "wPhoto" : 2959712,
        "username_1" : 2657200,
        "tsRegistered" : 2976064,
        "likes.id" : 483610400,
        "dmForCnt_1" : 2861600,
        "wPopularity3" : 573660864,
        "tags" : 4611264,
        "status" : 3311280,
        "birthday" : 2959712,
        "gender" : 3008768,
        "points" : 2869776,
        "employee" : 2174816,
        "manualSubscription" : 2338336,
        "facebookID_1" : 3916304,
        "facebookID" : 4161584,
        "lastActivity" : 2796192,
        "isFraud" : 1537088,
        "settingsDailyMatch" : 1545264
    },
    "ok" : 1
}

インデックス付きフィールドの更新に時間がかかると思いますか? 何か不足していますか?

アップデート:

100K を超えるドキュメントのみがこの問題を抱えていることに気付きました。他のドキュメントは急速に更新されています。

4

1 に答える 1

0

応答が遅いのは、埋め込まれたドキュメントのインデックスが原因でした。

> db.users.getIndices()
[
    {
        "v" : 1,
        "key" : {
            "likes.id" : 1
        },
        "ns" : "od.users",
        "name" : "likes.id"
    }
]

like属性を持つサンプルドキュメント:

> obj = db.users.findOne({"_id" : ObjectId("50710913a6427bfa2600000c")})
> Object.bsonsize(obj)
532162
> obj.likes.length
4770
> obj.likes[0]
{
    "id" : "103128829727364",
    "name" : "Jennifer Lopez",
    "category" : "Musician/band",
    "hidden" : false,
}

したがって、4770の埋め込みいいねドキュメントがあり、これらはlikes.id属性でインデックス付けされます。

このドキュメントで更新を実行すると、いいねには触れませんが、次のようになります。

> db.users.update({"_id" : ObjectId("50710913a6427bfa2600000c") },{$addToSet: {"otherPhotos" : "holipiuouiouioiuoi1"}})

時間がかかります:

> db.system.profile.find({op:"update"}).sort({ts:-1}).limit(1).pretty()
{
    "ts" : ISODate("2013-02-20T08:59:30.707Z"),
    "op" : "update",
    "ns" : "od.users",
    "query" : {
        "_id" : ObjectId("50710913a6427bfa2600000c")
    },
    "updateobj" : {
        "$addToSet" : {
            "otherPhotos" : "holipiuouiouioiuoi1"
        }
    },
    "idhack" : true,
    "nupdated" : 1,
    "keyUpdates" : 0,
    "numYield" : 0,
    "lockStats" : {
        "timeLockedMicros" : {
            "r" : NumberLong(0),
            "w" : NumberLong(1752759)
        },
        "timeAcquiringMicros" : {
            "r" : NumberLong(0),
            "w" : NumberLong(83)
        }
    },
    "millis" : 1752,
    "client" : "127.0.0.1",
    "user" : ""
}

しかし、インデックスを削除すると、非常に高速に動作します。

> db.users.dropIndex("likes.id")
{ "nIndexesWas" : 2, "ok" : 1 }
> db.users.update({"_id" : ObjectId("50710913a6427bfa2600000c") },{$addToSet: {"otherPhotos" : "holipiuouiouioiuoi12hkjhkjhkjhkjhkjhkjhkj"}})
> db.system.profile.find({op:"update"}).sort({ts:-1}).limit(1).pretty()
{
    "ts" : ISODate("2013-02-20T09:02:13.747Z"),
    "op" : "update",
    "ns" : "od.users",
    "query" : {
        "_id" : ObjectId("50710913a6427bfa2600000c")
    },
    "updateobj" : {
        "$addToSet" : {
            "otherPhotos" : "holipiuouiouioiuoi12hkjhkjhkjhkjhkjhkjhkj"
        }
    },
    "idhack" : true,
    "nupdated" : 1,
    "keyUpdates" : 0,
    "numYield" : 0,
    "lockStats" : {
        "timeLockedMicros" : {
            "r" : NumberLong(0),
            "w" : NumberLong(1137)
        },
        "timeAcquiringMicros" : {
            "r" : NumberLong(0),
            "w" : NumberLong(5)
        }
    },
    "millis" : 1,
    "client" : "127.0.0.1",
    "user" : ""
}

問題のあるインデックスが削除されると、「ポイント」にインデックスを追加することができ、元のクエリの応答時間はわずか1ミリ秒になりました。

> db.users.ensureIndex({points:1})
> db.users.getIndices()
[
    {
        "v" : 1,
        "key" : {
            "_id" : 1
        },
        "ns" : "od.users",
        "name" : "_id_"
    },
    {
        "v" : 1,
        "key" : {
            "points" : 1
        },
        "ns" : "od.users",
        "name" : "points_1"
    }
]
> db.users.update({"_id" : ObjectId("50710913a6427bfa2600000c") },{$inc: {"points" : 5}})
> db.system.profile.find({op:"update"}).sort({ts:-1}).limit(1).pretty()
{
    "ts" : ISODate("2013-02-20T09:12:37.664Z"),
    "op" : "update",
    "ns" : "od.users",
    "query" : {
        "_id" : ObjectId("50710913a6427bfa2600000c")
    },
    "updateobj" : {
        "$inc" : {
            "points" : 5
        }
    },
    "nscanned" : 1,
    "nupdated" : 1,
    "keyUpdates" : 1,
    "numYield" : 0,
    "lockStats" : {
        "timeLockedMicros" : {
            "r" : NumberLong(0),
            "w" : NumberLong(1225)
        },
        "timeAcquiringMicros" : {
            "r" : NumberLong(0),
            "w" : NumberLong(4)
        }
    },
    "millis" : 1,
    "client" : "127.0.0.1",
    "user" : ""
}
> 

したがって、Mongoの埋め込みドキュメントの配列にインデックスを追加すると、この配列サイズが非常に大きくなる可能性がある場合、更新のパフォーマンスが大幅に低下する可能性があるようです。

于 2013-02-20T09:07:32.947 に答える