MongoDB 是一种高性能、可伸缩性非常高的 NoSQL 数据库,被广泛应用于互联网企业中。但是,当数据量增加或者工作负载变化时,MongoDB 的性能可能会受到影响,出现性能瓶颈。本文将分享一些 MongoDB 性能调优的细节,帮助开发者解决性能问题,提升 MongoDB 的性能表现。
索引优化
- 使用前缀索引
前缀索引可以让查询更快,尤其是在文本搜索场景中。举例来说,如果我们有一个字符串类型的字段,需要用其在查询中进行搜索,但是这个字段非常长,我们可以只取它的前几个字符进行索引,这样可以减少索引的大小,提高查询效率。
db.myCollection.createIndex({myField:1},{name:"myIndex",collation:{locale:"en_US",strength:2},w:1,length:10})
- 创建复合索引
对于经常同时查询多个字段的场景,应该创建复合索引。如下代码创建了一个基于字段 "fieldA" 和 "fieldB" 的复合索引:
db.myCollection.createIndex({fieldA:1,fieldB:-1})
复合索引可以极大提高查询效率。务必注意,所创建的复合索引字段顺序必须与查询时给定的顺序一致,否则索引将无法使用。
- 删除无用索引
一个 MongoDB 数据库中可能有很多索引,但并不是所有的索引都会被使用。无用的索引会占用磁盘空间,导致查询速度变慢。因此,需要定期检测和删除无用索引。
我们可以使用以下命令查看所有数据库中的索引信息:
db.adminCommand({listDatabases:1})
数据库和集合优化
- 分区和分片
分片可以提高 MongoDB 的水平扩展性,多个 Shard 之间的数据分散在不同的服务器上,提高了整个系统的容量和负载均衡性。可以通过以下命令创建分片集群:
mongos --configdb config_shard1/localhost:27018,localhost:27019,localhost:27020 --chunkSize 1 --fork --logpath shard1.log mongos --configdb config_shard2/localhost:27018,localhost:27019,localhost:27020 --chunkSize 1 --fork --logpath shard2.log
- 关闭 MongoDB 日志
默认情况下,MongoDB 中会记录所有的操作记录,这会导致大量的磁盘空间被占用。因此,我们可以关闭 MongoDB 的操作日志,减少磁盘写入量,提高性能。
在 MongoDB 配置文件中添加以下命令:
systemLog: destination: file path: /var/log/mongodb/mongod.log logRotate: reopen verbosity: 0
- 使用 TTL 索引自动删除过期数据
TTL(time to live)索引可以自动删除过期的数据,让数据库空间得到释放。可以通过以下命令创建一个 TTL 索引:
db.myCollection.createIndex({createdAt: 1}, {expireAfterSeconds: 3600})
这里 "createdAt" 就是你需要设置过期时间的字段,"expireAfterSeconds" 则是过期秒数。所有 createdAt 字段值在指定时间之前的文档都会被自动删除。
查询优化
- 使用 explain 命令分析查询执行计划
explain 命令可以展示 MongoDB 查询的执行计划,提供一个分析查询效率的好方法。可以通过以下命令查看该命令的执行计划:
db.myCollection.find({fieldA:"a"}).explain()
- 使用索引 hint 提示器
在某些搜索场景下,MongoDB 可能不能自主判断出最佳的索引,这时我们可以使用 hint 命令指定索引进行搜索。
db.myCollection.find({fieldA:"a"}).hint({fieldA: 1})
- 使用 covered query 避免回溯查询
如果查询只需要通过索引即可完成,MongoDB 不需要回溯到数据存储区,这就是 "covered query"。可以通过以下命令查看你的查询是否是 covered query:
db.myCollection.find({fieldA:"a"},{_id:0,fieldB:1}).explain()
- 使用 Batch size 减少网络负载
MongoDB 中的批处理可以减少数据库和客户端之间的交互次数,提高查询效率。可以通过以下命令将查询结果拆成小批次返回:
db.myCollection.find().batchSize(10);
集合锁定和文件锁定
MongoDB 采用了读写锁定机制,在保证数据一致性的前提下,可以支持多用户同时读取和操作数据。
在 MongoDB 中,一次操作可能会对多个文件进行读写,为了保证数据一致性,MongoDB 引入了文件锁(文件级别锁)和集合锁(集合级别锁)两个概念。
- 文件锁定
针对整个 MongoDB 实例中的所有数据库文件,MongoDB 采用了 MMAPv1 存储引擎,默认进行文件锁定操作。除非有特殊需求,在一般情况下,我们不需要去担心文件锁定的问题。
- 集合锁定
MongoDB 采用了基于 B树 的存储引擎,在针对单个文档的操作时,MongoDB 需要进行集合锁。集合锁是一个悲观的锁定方式,每次只允许一个线程进行写操作。
如果我们在写数据的时候,需要非常小心的避免锁定冲突,这会影响系统的性能。在实践中,可以通过以下几种方式避免集合锁定冲突:
- 缩小批处理操作,避免同时对大量文档进行操作
- 为经常操作的数据缓存一个副本,减少锁定时间
- 合理使用事务
总结
以上就是 MongoDB 性能调优的一些细节分享。在实际开发中,我们需要根据自己的应用场景和实际数据量分析,不同场景的应用需要不同的优化策略。通过上述方法,我们可以优化查询语句、减少索引和数据存储占用,提高查询效率和数据库读写性能。值得注意的是,从本质上看,优化只能是一个解决问题的起步,仅仅是弥补一些不合理的设计或者代码做法。有了优化,我们可以让 MongoDB 在大部分的场景下表现得更好,但是在特殊或者极其复杂的情况下还需要更加高级的技术手段进行优化。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/64f986d1f6b2d6eab3103fe0