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:使 emailId 唯一字段[重复]
mongoDB (mongoose增删改查聚合索引连接备份与恢复监控等等)