生产代码中的猫鼬索引


123

根据Mongoose 文档中关于MongooseJSMongoDB/的内容Node.js

当您的应用程序启动时,Mongoose会自动调用ensureIndex架构中的每个已定义索引。虽然有利于开发,但建议在生产中禁用此行为,因为创建索引会严重影响性能。通过将autoIndex架构选项设置为false来禁用该行为。

这似乎指示从Mongoose删除自动索引,然后再进行部署以优化Mongoose,这是从指示Mongo在应用程序启动时遍历所有索引开始的,这似乎是有道理的。

在生产代码中处理索引的正确方法是什么?也许外部脚本应该生成索引?或者,ensureIndex如果单个应用程序是集合的唯一读取器/写入器,也许是不必要的,因为每当发生DB写操作时,该应用程序都会继续索引?

编辑:补充,MongoDB中提供了良好的文档如何做索引,但不为什么还是明确索引指令应该做的。在我看来,编写应用程序应在具有现有索引的集合上自动使索引保持最新,这ensureIndex实际上是一次性的事情(在应用新索引时完成),在这种情况下,猫鼬autoIndex应该是在正常服务器重启下无操作。

Answers:


133

我从未理解过为什么Mongoose文档如此广泛地建议禁用autoIndex生产。一旦添加了索引,随后的ensureIndex调用将简单地看到该索引已经存在,然后返回。因此,它仅在首次创建索引时才对性能产生影响,并且那时集合通常是空的,因此无论如何创建索引都会很快。

我的建议是保持autoIndex启用状态,除非您遇到特殊情况会给您带来麻烦。例如,如果您想向具有数百万个文档的现有集合中添加新索引,并且希望对其创建时间进行更多控制。


10
我有一个问题要补充...如果我将其设置为假,该怎么办?当我插入数据或需要显式创建数据时,将创建索引。很抱歉,如果这是一个新手问题,但如果您回答的话,会很有帮助。
Saransh Mohapatra 2013年

5
@SaranshMohapatra如果autoIndex为false,则需要在模型上调用sureIndexes以创建其索引。
JohnnyHK 2013年

是否比每次定义模型都要调用一次?
Saransh Mohapatra 2013年

定义(编译)模型时,@ SaranshMohapatra。我在第一次启动该应用程序时就这样做了。现在,很难想到的是决定删除所有索引并重新创建它们,以防万一您更改架构。
莫斯,

3
@JohnnyHK快到2016年了,您仍然同意您的回答吗?
亚历山大·米尔斯

41

尽管我同意接受的答案,但值得注意的是,根据MongoDB手册,这不是在生产服务器上添加索引的推荐方式:

如果您的应用程序包含sureIndex()操作,并且因其他操作问题而没有索引,则构建索引可能会对数据库的性能产生严重影响。

为避免性能问题,请确保您的应用程序在启动时使用getIndexes()方法或驱动程序的等效方法检查索引,并在不存在适当索引的情况下终止。在指定的维护时段内,始终使用单独的应用程序代码在生产实例中构建索引。

当然,这实际上取决于应用程序的结构和部署方式。例如,如果您要部署到Heroku,而您没有使用Heroku的preboot功能,那么您的应用程序可能在启动期间根本不满足请求,因此在那时创建索引可能是安全的。

除此之外,从接受的答案中:

因此,它仅在首次创建索引时才对性能产生影响,并且那时集合通常是空的,因此无论如何创建索引都将很快。

如果您已成功获取数据模型和查询的详细信息,那很好,通常是这样。但是,如果要向应用程序添加新功能,并且对不带索引的属性进行新的数据库查询,则通常会发现自己向包含许多现有文档的集合中添加了索引。

这是您需要谨慎添加索引并仔细考虑这样做对性能的影响的时候。例如,您可以在后台创建索引

db.ensureIndex({ name: 1 }, { background: true });

3
好的,因此只有在为每个集合触发了所有sureIndex回调之后,您才需要启动服务器。
亚历山大·米尔斯

@AlexMills您如何确保?
lonelymo '16

async.each(Object.keys(models),function(key,cb){models [key] .ensureIndexes(cb)},cb)
Alexander Mills

只需在每个猫鼬模型上调用sureIndexes,等待所有操作完成,然后启动服务器即可;我还建议您在启动服务器之前也要等待数据库连接发生
Alexander Mills

2
没有ensureIndex了。有createIndex代替。我对吗?
杰克·

1

使用此块代码处理生产模式:

const autoIndex = process.env.NODE_ENV !== 'production';
mongoose.connect('mongodb://localhost/collection', { autoIndex });
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.