在MongoDB中,我使用了一个大型查询,我将如何创建复合索引或单个索引,所以我的响应时间提升了

时间:2017-10-26 06:26:58

标签: node.js mongodb mongoose

在我的项目中,我有一个帖子集合,这是方案:

posts:{
        title:            {type: String, required: false},
        text:             {type: String, required: false},
        plainDescription: {type: String, required: false},
        isBlog:           {type: Boolean,default: false},
        type:             {type: String, required: true, default:'USER', enum:["USER","GROUP"]},
        information:{
            tags:[],
            users:[],
            groups:[],
            likes:[],
            likesCount:   {type: Number, default: 0},           
            dislikes:[],
            dislikesCount:{type: Number, default: 0},
            spams:[],
            spamsCount:   {type: Number, default: 0},
            shares:[],
            sharesCount:  {type: Number, default: 0},
            comments:[],
            commentsCount:{type: Number, default: 0},
            reply:[],
            favorite: [],
            favoriteCount:{type: Number, default: 0},
            replyCount:   {type: Number, default: 0}
        },
        authorId            : { type: String, required: true},// Can be user Id or Group Id
        authorName          : { type: String, required: false},
        isReply             : { type: Boolean, default: false},
        replyOf             : { type: String, default: "",nullable: true, references: 'posts._id'},
        isQuoteReyell       : { type: Boolean, default: false},
        quoteReyellOf       : { type: String, default: "",nullable: true, references: 'posts._id'},
        createdAt           : { type: Date, default: Date.now},
        createdBy           : { type: String, required: false, references: 'users._id'},
        creatorName         : { type: String, required: true, references: 'users.userName'},
        updatedAt           : { type: Date, required: false,default: Date.now},
        updatedBy           : { type: String, required: false, references: 'users._id'},
        updatorName         : { type: String, required: false, references: 'users.userName'},
        publishedAt         : { type: Date, required: false},
        isBlockedByAdmin    : {type:  Boolean,default: false},
        isDelete            : {type:  Boolean,default: false},
        isRss               : {type:  Boolean,default: false},
        updatedObj          : [],
        sportName           : {type: String, default: ''},
        teamObj             : []
    },

并根据我的要求,这是查询:

[{"$match":{"$and":[{"$or":[{"$and":[{"createdBy":{"$in":["5754c557bd961f3751ddd830"]}},{"createdAt":{"$lt":"2017-10-26T06:17:32.533Z"}},{"information.shares":{"$elemMatch":{"userId":{"$in":["5754c557bd961f3751ddd830"]},"sharedAt":{"$not":{"$gt":"2017-10-26T06:17:32.533Z"}}}}}]},{"$and":[{"isQuoteReyell":{"$ne":true}},{"updatedObj":{"$elemMatch":{"userId":{"$in":["5754c557bd961f3751ddd830"]},"type":"reyell","updatedAt":{"$not":{"$gt":"2017-10-26T06:17:32.533Z"}}}}},{"isReply":false}]},{"$and":[{"information.shares":{"$elemMatch":{"userId":{"$in":["5754c557bd961f3751ddd830"]},"sharedAt":{"$not":{"$gt":"2017-10-26T06:17:32.533Z"}}}}}]},{"$and":[{"isReply":true},{"createdBy":{"$in":["5754c557bd961f3751ddd830"]}},{"updatedAt":{"$lt":"2017-10-26T06:17:32.533Z"}}]},{"$and":[{"updatedObj":{"$elemMatch":{"userId":{"$in":["5754c557bd961f3751ddd830"]},"type":{"$ne":"reyell"},"updatedAt":{"$not":{"$gt":"2017-10-26T06:17:32.533Z"}}}}}]},{"$and":[{"createdBy":{"$in":["5754c557bd961f3751ddd830"]}},{"createdAt":{"$lt":"2017-10-26T06:17:32.533Z"}},{"isBlog":false},{"information.shares":{"$elemMatch":{"userId":{"$in":["5754c557bd961f3751ddd830"]},"sharedAt":{"$not":{"$gt":"2017-10-26T06:17:32.533Z"}}}}}]},{"$and":[{"isQuoteReyell":{"$ne":true}},{"updatedObj":{"$elemMatch":{"userId":{"$in":["5754c557bd961f3751ddd830"]},"type":"reyell","updatedAt":{"$not":{"$gt":"2017-10-26T06:17:32.533Z"}}}}},{"isReply":false}]},{"information.shares":{"$elemMatch":{"userId":{"$in":["5754c557bd961f3751ddd830"]},"sharedAt":{"$not":{"$gt":"2017-10-26T06:17:32.533Z"}}}}},{"$and":[{"isReply":true},{"createdBy":{"$in":["5754c557bd961f3751ddd830"]}},{"updatedAt":{"$lt":"2017-10-26T06:17:32.533Z"}},{"information.shares":{"$elemMatch":{"userId":{"$in":["5754c557bd961f3751ddd830"]},"sharedAt":{"$not":{"$gt":"2017-10-26T06:17:32.533Z"}}}}}]},{"$and":[{"information.shares":{"$elemMatch":{"userId":{"$in":["5754c557bd961f3751ddd830"]},"sharedAt":{"$not":{"$gt":"2017-10-26T06:17:32.533Z"}}}}},{"updatedObj":{"$elemMatch":{"userId":{"$in":["5754c557bd961f3751ddd830"]},"type":{"$ne":"reyell"},"updatedAt":{"$not":{"$gt":"2017-10-26T06:17:32.533Z"}}}}}]}]},{"isBlockedByAdmin":false},{"isDelete":false}]}},{"$unwind":"$updatedObj"},{"$match":{"$or":[{"$and":[{"updatedObj.type":"reyell"},{"updatedObj.userId":{"$in":["5754c557bd961f3751ddd830"]}}]},{"$and":[{"updatedObj.type":"create"}]}]}},{"$group":{"_id":"$_id","updated":{"$last":"$updatedObj"},"post":{"$last":"$$ROOT"}}},{"$sort":{"updated.updatedAt":-1}},{"$limit":15}]

请帮助我,对于哪一栏,我应该创建一个索引或复合索引,这样可以增加响应时间。

1 个答案:

答案 0 :(得分:3)

通常,您需要在最重要/频繁查询中最常用作过滤条件的字段上放置索引,首先从最具选择性的字段开始。有一些不错的guidance on the topic as part of the MongoDB documentation。因为你有很多$or s,所以对你的案例特别感兴趣的一个陈述可能就是这样:

  

通常,MongoDB只使用一个索引来完成大多数查询。   但是,$或查询的每个子句可以使用不同的索引,和   从2.6开始,MongoDB可以使用多个索引的交集。

然而,最重要的是使用explain()来衡量,衡量,衡量和查看查询执行计划。原因是您很可能会遇到应用程序需要支持的不同类型的查询,并且您需要在某些时候进行权衡,在这种情况下您必须在索引维护成本之间进行选择(例如write locks期间索引更新和磁盘空间要求)以及理论上最快的解决方案,其中单个查询中使用的所有字段都由单个索引覆盖。

整个索引主题有点模糊,严重依赖于您的精确场景:

  • 您的数据是否经过大量更新,并且写入需要超快(您需要更少/更小的索引),还是您的数据非常稳定,频繁读取必须快速(使用更多/更大的索引) )?
  • 您需要支持哪些类型的查询?他们的过滤器有多相似?过滤器的某些组合是否会比其他组合更可能?哪些查询需要执行得好,哪些查询可能会慢一点?
  • 您的潜在索引字段中的数据如何分发?
  • 等......

您将找不到帮助您的所有查询执行最佳操作的单一索引。而且,当添加更多索引或更改现有索引时,这可能导致查询优化器停止对某些查询使用某些索引,并选择不同的执行计划,而这可能是也可能不需要。因此,在对索引或物理数据布局(硬件设置,分片......)进行任何更改时,请测量所有重要信息。最后,您应该随着数据量的增长定期衡量您的查询效果,除非它的分布在预测上是统一的。

简而言之:寻找迭代方法并首先添加索引(我建议在isBlockedByAdminisDeleteinformation.shares.userId添加一个)然后衡量你的查询性能,然后根据您的发现(再次,再次,......)优化您的索引。