MongoDB/Mongoose 索引使查询更快还是变慢?

Posted

技术标签:

【中文标题】MongoDB/Mongoose 索引使查询更快还是变慢?【英文标题】:MongoDB/Mongoose index make query faster or slow it down? 【发布时间】:2015-10-22 16:12:20 【问题描述】:

我有一个这样的文章模型:

var ArticleSchema = new Schema(

    type: String
    ,title: String
    ,content: String
    ,hashtags: [String]

    ,comments: [
        type: Schema.ObjectId
        ,ref: 'Comment'
    ]

    ,replies: [
        type: Schema.ObjectId
        ,ref: 'Reply'
    ]

    , status: String
    ,statusMeta: 
        createdBy: 
            type: Schema.ObjectId
            ,ref: 'User'
        
        ,createdDate: Date
        , updatedBy: 
            type: Schema.ObjectId
            ,ref: 'User'
        
        ,updatedDate: Date

        ,deletedBy: 
            type: Schema.ObjectId,
            ref: 'User'
        
        ,deletedDate: Date

        ,undeletedBy: 
            type: Schema.ObjectId,
            ref: 'User'
        
        ,undeletedDate: Date

        ,bannedBy: 
            type: Schema.ObjectId,
            ref: 'User'
        
        ,bannedDate: Date
        ,unbannedBy: 
            type: Schema.ObjectId,
            ref: 'User'
        

        ,unbannedDate: Date
    
, minimize: false)

当用户创建或修改article时,我将创建主题标签

ArticleSchema.pre('save', true, function(next, done) 
    var self = this
    if (self.isModified('content')) 
        self.hashtags = helper.listHashtagsInText(self.content)
    
    done()
    return next()
)

例如,如果用户写"Hi, #greeting, i love #friday",我会将['greeting', 'friday'] 存储在标签列表中。

我正在考虑为主题标签创建索引,以便更快地查询主题标签。但是从猫鼬手册中,我发现了这个:

当您的应用程序启动时,Mongoose 会自动调用 确保架构中每个已定义索引的索引。猫鼬会打电话 为每个索引顺序确保索引,并在上发出一个“索引”事件 所有 ensureIndex 调用成功或存在时的模型 一个错误。虽然很适合开发,但建议使用此行为 在生产中被禁用,因为索引创建可能会导致显着 性能影响。通过设置 autoIndex 禁用该行为 您的架构选项为 false。

http://mongoosejs.com/docs/guide.html

那么对于 mongoDB/Mongoose,索引是更快还是更慢?

另外,即使我创建了类似的索引

  hashtags:  type: [String], index: true 

如何在查询中使用索引?或者对于普通查询,它会神奇地变得更快,例如:

   Article.find(hashtags: 'friday')

【问题讨论】:

您是否阅读了.createIndex() 的核心文档?具体来说:“如果同时调用多个具有相同索引规范的createIndex()方法,只有第一个操作会成功,其他操作无效。”.索引也需要写入成本,但它们会加快读取速度。这是索引的基本概念。有很多文档可以解释索引的作用。也许做一些阅读。 @BlakesSeven 我正在使用 Mongoose,我认为这是一个 mongoDB 包装器。官方文档让我感到困惑,建议在生产中将其关闭 【参考方案1】:

你看错了

您误读了引用块的意图,即.ensureIndex()(现已弃用,但仍由猫鼬代码调用)在上下文中实际执行的操作。

在 mongoose 中,您可以在架构或模型级别定义适合您设计的索引。猫鼬“自动”为您做的事情是在连接时检查每个已注册的模型,然后为提供的索引定义调用适当的 .ensureIndex() 方法。

这实际上是做什么的?

嗯,在大多数情况下,在您之前已经启动应用程序并运行 .ensureIndexes() 方法之后是绝对没有。这有点夸大其词,但或多或​​少听起来是对的。

因为已经在服务器集合上创建了索引定义,所以后续调用不会做任何事情。即,它不会删除索引并“重新创建”。因此,一旦创建了索引本身,真正的成本基本上就没有了。

创建索引

因此,由于 mongoose 只是标准 API 之上的一层,createIndex() 方法包含正在发生的所有细节。

这里有一些细节需要考虑,例如索引构建可能发生在“后台”中,虽然这对您的应用程序的干扰较小,但它确实需要自己付出代价。值得注意的是,“后台”生成的索引大小将比在前台构建时更大,从而阻塞其他操作。

此外,所有索引都是有成本的,特别是在磁盘使用方面,以及在收集数据本身之外写入额外信息的额外成本。

索引的优点是“搜索”索引中包含的值比搜索整个集合并匹配可能的条件要快得多。

这些是与索引相关的基本“权衡”。

部署模式

回到文档中的quoted block,这个建议背后有一个真正的意图。

在部署模式中很典型,尤其是在数据迁移中按此顺序执行操作:

    将数据填充到相关集合/表中 为与您的需求相关的集合/表数据启用索引

这是因为创建索引需要成本,如前所述,希望从索引构建中获得最佳大小,同时避免每个文档插入也产生写入索引条目的开销当您批量执行此“加载”时。

这就是索引的用途,它们是成本和收益,并且解释了 mongoose 文档中的信息。

不过,总的来说,我建议阅读Database Indexes,了解它们是什么以及它们做了​​什么。想想走进图书馆找一本书。入口处有卡片索引。你会在图书馆里四处走走寻找你想要的书吗?还是您在卡片索引中查找它以找到它的位置?该索引需要花费一些时间来创建并保持更新,但它节省了“您”在整个图书馆走动的时间,以便您可以找到您的书。

【讨论】:

所谓的性能影响只有在我将现有数据迁移到它的情况下才适用? @OMGPOP 正如已经解释的那样,“块”的意思是在“生产”环境中,您通常希望更好地控制何时创建或修改索引,而不是让应用程序自行启动创建.当索引已经存在时,实际影响可能不大。这就是上面所有内容的解释,就像每次插入/修改都需要花费时间来编写索引一样,但会加快读取过程,避免扫描集合以查找匹配项。 "在“生产”环境中,您通常希望更好地控制何时创建或修改索引,而不是让应用程序自行启动创建。"你的意思是?我们在保存数据的时候不是一直在创建索引吗? 另外,我编辑了我的帖子并在最后添加了一个小问题。我们是否需要为查询做任何额外的工作才能使用索引? @OMGPOP 否。创建索引和在写入时“更新”索引是两件不同的事情。您正在阅读的块不是“不要使用索引”。而是“建议”“关闭自动创建” 并在已部署应用程序的外部管理流程【参考方案2】:

这可能就是你要找的东西

https://www.npmjs.com/package/mongoose-text-search

【讨论】:

以上是关于MongoDB/Mongoose 索引使查询更快还是变慢?的主要内容,如果未能解决你的问题,请参考以下文章

mongodb / mongoose 中的部分索引

mongoDb/Mongoose:使 emailId 唯一字段[重复]

mongodb mongoose中的重复键错误索引

mongoDB (mongoose增删改查聚合索引连接备份与恢复监控等等)

E11000 mongodb mongoose 中的重复键错误索引

E11000 mongodb mongoose 中的重复键错误索引