MONGODB简单查询太长时间无法执行为什么?

时间:2017-12-08 11:32:08

标签: mongodb

我的查询需要花费很多时间....

  • 130,000份文件 - > 70毫秒(当地)
  • 11,000份文件 - > 80ms(当地)
  • 1,600份文件 - > 2ms(本地)(其他基础,更复杂的查询)

为什么前两个会比第三个更复杂呢?

使用130.000个文档(60-69ms)查询

{
    "_id" : ObjectId("58e669e81a5696098804e0ae"),
    "target" : "mysuperlogin",
    "type" : "auth",
    "key" : "try",
    "useragent" : "Mozilla/5.0 (iPhone; CPU iPhone OS 10_2_1 like Mac OS X) AppleWebKit/602.4.6 (KHTML, like Gecko) Mobile/14D27",
    "ip" : "X.X.X.X",
    "creation_date" : ISODate("2017-04-06T16:16:40.584Z"),
    "__v" : 0
}

db.collection.aggregate(
[
    {
        $match:
        {
            'type':          'auth',
            'target':        params.authlogin,
            'ip':            'X.X.X.X',
            'creation_date': { $gte: date }
        },
        { $group: { _id: '$key', total: { $sum: 1 } } },
        { $sort:   { _id: -1 }}
    }
])

查询11.000个文档(77-90ms)

{
    "_id" : ObjectId("5a2a6b17aafee9dcf4000422"),
    "target" : "mysuperlogin",
    "type" : "auth",
    "key" : "try",
    "useragent" : "Mozilla/5.0 (iPhone; CPU iPhone OS 10_2_1 like Mac OS X) AppleWebKit/602.4.6 (KHTML, like Gecko) Mobile/14D27",
    "events" : [
        {
            "creation_date" : ISODate("2017-12-05T08:45:37.217Z"),
            "ip" : "X.X.X.X"
        },
        {
            "creation_date" : ISODate("2017-12-05T08:45:37.010Z"),
            "ip" : "X.X.X.X"
        },
        {
            "creation_date" : ISODate("2017-12-05T08:45:37.111Z"),
            "ip" : "X.X.X.X"
        },
        {
            "creation_date" : ISODate("2017-12-05T08:45:39.759Z"),
            "ip" : "X.X.X.X"
        },
        {
            "creation_date" : ISODate("2017-12-05T08:45:40.054Z"),
            "ip" : "X.X.X.X"
        },
        {
            "creation_date" : ISODate("2017-12-05T08:47:36.471Z"),
            "ip" : "X.X.X.X"
        }
    ]
}

db.collection.aggregate(
[
    {
        $match:
        {
            'type':                 'auth',
            'target':               'mysuperlogin',
            'events.ip':            'X.X.X.X',
            'events.creation_date': { $gte: new Date('2017-12-05T08:30:00.471Z') }
        }
    },
    { $unwind: '$events' },
    { $match:  { 'events.creation_date': { $gte: new Date('2017-12-05T08:30:00.471Z') } } },
    { $group:  { _id: '$key', total: { $sum: 1 } } },
    { $sort:   { _id: -1 }}
])

使用1.600文档查询(3-4ms)

{
    "_id" : ObjectId("58f0ce79e07b3e6c24c5a453"),
    "groups" : [
        {
            "name" : "defaut",
            "company_id" : ObjectId("58e4f31cf8eca22e06167736"),
            "apikey" : "XXXXXXXXXXXXXXXXXXXXXXXXXXX",
            "level" : 1,
            "expire_date" : ISODate("2018-12-31T00:00:00Z"),
            "creation_date" : ISODate("2017-04-14T13:28:25.122Z")
        }
    ],
    "sessions" : [
        {
            "apikey" : "XXXXXXXXXXXXXXXXXXXXXXXXXXX",
            "token" : "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY",
            "ip" : "X.X.X.X",
            "expire_date" : ISODate("2017-05-14T13:35:13.533Z"),
            "_id" : ObjectId("58f0d0113675136beb64c5a1")
        },
        {
            "apikey" : "XXXXXXXXXXXXXXXXXXXXXXXXXXX",
            "tokenassets" : "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY",
            "ip" : "X.X.X.X",
            "expire_date" : ISODate("2017-05-14T13:35:13.533Z"),
            "_id" : ObjectId("58f0d0113675136beb64c5a1")
        }
    ],
    "infos" : {
        "login" : "mysuperlogin",
        "mail" : "mysuperlogin@mymail.com",
        "password" : "CRYPTEDCRYPTEDCRYPTEDCRYPTEDCRYPTEDCRYPTEDCRYPTEDCRYPTEDCRYPTEDCRYPTEDCRYPTEDCRYPTEDCRYPTEDCRYPTEDCRYPTED",
        "firstname" : "my",
        "lastname" : "superlogin",
        "creation_date" : ISODate("2017-04-14T13:28:25.124Z")
    },
    "__v" : 0
}

db.collection.aggregate(
[
    {
        $match:
        {
            $and:
            [
                {$or:
                [
                    {'infos.login': 'XXXXXXX'},
                    {'infos.mail':  'XXXXXXX'.toLowerCase()}
                ]},
                {$or:
                [
                    {'infos.password': 'XXXXXXX'},
                    {
                        sessions:
                        {
                            $elemMatch:
                            {
                                'apikey': 'XXXXXXX',
                                'token':  'XXXXXXX'
                            }
                        }
                    },
                    {
                        sessions:
                        {
                            $elemMatch:
                            {
                                'apikey': 'XXXXXXX',
                                'tokenassets':  'XXXXXXX'
                            }
                        }
                    }
                ]}
            ]
        }
    },
    {
        $lookup:
        {
            from: 'othercollection',
            localField: '_id',
            foreignField: 'user_id',
            as: 'othercollection'
        }
    },
    { $unwind: '$othercollection' },
    {
        $project: { 'groups._id': 0, 'othercollection.groups._id': 0 }
    }
])

架构(使用mongoose nodejs创建):

// Collection 1 (130.000 docs)
const historiesSchema = new mongoose.Schema(
{
    user_id:    mongoose.Schema.Types.ObjectId,
    apikey:     String,
    ip:         String,
    target:     String,
    type:       String,
    key:        String,
    value:      String,
    level:      Number,
    useragent:  String,
    creation_date:
    {
        type:    Date,
        default: Date.now
    }
});


// Collection 2 (11.000 docs)
const eventsSchema = new mongoose.Schema(
{
    ip: String,
    creation_date:
    {
        type:    Date,
        default: Date.now
    }
},
{
    _id : false
});
const histories2Schema = new mongoose.Schema(
{
    user_id:   mongoose.Schema.Types.ObjectId,
    apikey:    String,
    ip:        String,
    target:    String,
    type:      String,
    key:       String,
    value:     String,
    level:     Number,
    useragent: String,
    events:    [eventsSchema]
});


// Collection 3 (1.600 docs)
const sessionSchema = new mongoose.Schema(
{
    apikey:      String,
    token:       String,
    tokenassets: String,
    ip:          String,
    expire_date: Date
},
{
    _id : false
});
const userSchema = new mongoose.Schema(
{
    infos:
    {
        login:       String,
        mail:        String,
        nomail:      Boolean,
        password:    String,
        firstname:   String,
        lastname:    String,
        suspend:     Boolean,
        creation_date:
        {
            type:    Date,
            default: Date.now
        }
    },
    lostpass:
    {
        token:         String,
        creation_date: Date
    },
    sessions: [sessionSchema]
});

1 个答案:

答案 0 :(得分:2)

从您的Schemata中可以明显看出,您没有使用任何索引。 检查this页面,了解如何使用Mongoose创建索引。以下是该页面上显示的示例:

var animalSchema = new Schema({
  name: String,
  type: String,
  tags: { type: [String], index: true } // field level
});

animalSchema.index({ name: 1, type: -1 }); // schema level

此外,当您运行.explain()时,您应该能够看到它正在执行完整的集合扫描。您可以在 queryPlanner 下找到 winnerPlan ,然后您会看到字段stage: "COLLSCAN"。这会破坏您数据库的性能。 在您将经常用于搜索的字段上创建索引。不要过度使用索引,但也不要吝啬。

我还建议您阅读documentation on indexes of MongoDB