面试题答案
一键面试索引优化策略
- 复合索引:
- 对于基于多个字段的组合条件查询,创建复合索引。例如,如果经常按
field1
、field2
和field3
组合查询,创建索引db.collection.createIndex({field1: 1, field2: 1, field3: 1})
。索引字段顺序很重要,应将选择性高(即值的唯一性高)的字段放在前面,以提高查询效率。
- 对于基于多个字段的组合条件查询,创建复合索引。例如,如果经常按
- 覆盖索引:
- 尽量使用覆盖索引,即查询所需要的所有字段都包含在索引中。这样查询时MongoDB可以直接从索引中获取数据,而不需要回表操作,减少磁盘I/O。例如,如果查询
field1
、field2
,且field3
的值不关心,可以创建索引db.collection.createIndex({field1: 1, field2: 1})
,然后查询db.collection.find({field1: value1, field2: value2}, {field1: 1, field2: 1, _id: 0})
。这里_id
默认会在索引中,如果不需要显示返回,可设置为0。
- 尽量使用覆盖索引,即查询所需要的所有字段都包含在索引中。这样查询时MongoDB可以直接从索引中获取数据,而不需要回表操作,减少磁盘I/O。例如,如果查询
- 数组索引:
- 对于数组内元素的查询,创建数组索引。例如,如果文档中有数组
arrayField
,且经常查询数组中包含某个值的文档,可创建索引db.collection.createIndex({"arrayField": 1})
。对于嵌套数组或需要更复杂查询的数组结构,可能需要使用多键索引等更高级的技术。
- 对于数组内元素的查询,创建数组索引。例如,如果文档中有数组
- 部分索引:
- 当写操作频繁且某些查询只针对部分数据时,使用部分索引。例如,只对
status
为"active"
的文档进行特定查询,可创建部分索引db.collection.createIndex({field1: 1}, {partialFilterExpression: {status: "active"}})
。这样可以减少索引维护成本,提高写性能,同时不影响特定查询的读性能。
- 当写操作频繁且某些查询只针对部分数据时,使用部分索引。例如,只对
平衡读写性能与减少锁争用
- 读写分离:
- 利用MongoDB的副本集功能,将读操作分配到从节点。在应用程序配置中,设置读偏好为
secondaryPreferred
或secondary
,这样大部分读操作会从从节点获取数据,减轻主节点的压力,减少读写锁争用。例如在Node.js中使用mongodb
驱动:
const { MongoClient } = require('mongodb'); const uri = "mongodb://primary:27017,secondary1:27017,secondary2:27017/?replicaSet=myReplicaSet&readPreference=secondaryPreferred"; const client = new MongoClient(uri);
- 利用MongoDB的副本集功能,将读操作分配到从节点。在应用程序配置中,设置读偏好为
- 合理使用索引:
- 避免创建过多不必要的索引,因为每个索引都需要额外的磁盘空间和维护成本。过多索引会增加写操作时的锁争用,因为每次写操作都可能需要更新多个索引。定期评估索引的使用情况,删除不再使用的索引,可使用
db.collection.totalIndexSize()
查看索引占用空间,以及db.collection.find().explain("executionStats").queryPlanner.winningPlan.inputStage.indexName
查看查询使用的索引。
- 避免创建过多不必要的索引,因为每个索引都需要额外的磁盘空间和维护成本。过多索引会增加写操作时的锁争用,因为每次写操作都可能需要更新多个索引。定期评估索引的使用情况,删除不再使用的索引,可使用
相关配置与参数
- 副本集配置:
- 在副本集配置文件中,可以调整成员节点的优先级,例如:
{ "_id": "myReplicaSet", "version": 1, "members": [ { "_id": 0, "host": "primary:27017", "priority": 2 }, { "_id": 1, "host": "secondary1:27017", "priority": 1 }, { "_id": 2, "host": "secondary2:27017", "priority": 1 } ] }
- 优先级高的节点更有可能成为主节点,可根据读写负载合理分配优先级。
- MongoDB配置文件:
- 在
mongod.conf
中,可以调整storage.wiredTiger.engineConfig.cacheSizeGB
参数,设置WiredTiger存储引擎的缓存大小。适当增大缓存可以提高读写性能,因为更多的数据和索引可以缓存在内存中,减少磁盘I/O。例如:
storage: wiredTiger: engineConfig: cacheSizeGB: 2
- 还可以调整
operationProfiling
相关参数来监控和分析读写操作性能,例如:
operationProfiling: mode: "slowOp" slowOpThresholdMs: 100
- 这里设置了只记录执行时间超过100毫秒的慢操作,通过分析这些慢操作来进一步优化索引和查询。
- 在