面试题答案
一键面试索引创建策略
- 复合索引:
- 分析常见的查询条件组合,将经常一起用于查询的字段组合成复合索引。例如,如果业务经常按
user_id
和timestamp
查询,可创建{user_id: 1, timestamp: 1}
的复合索引,其中1表示升序, -1表示降序。这样能显著提升相关查询的读性能。 - 复合索引的顺序很关键,应将选择性高(即唯一值多)的字段放在前面,以减少索引扫描的范围。
- 分析常见的查询条件组合,将经常一起用于查询的字段组合成复合索引。例如,如果业务经常按
- 覆盖索引:
- 对于某些查询,若查询结果所需的字段都包含在索引中,创建覆盖索引。例如,查询只需要
user_name
和email
字段,且经常按user_id
查询,可创建{user_id: 1, user_name: 1, email: 1}
的覆盖索引。这样MongoDB无需再从文档中读取数据,直接从索引就能返回结果,大大提高读性能。
- 对于某些查询,若查询结果所需的字段都包含在索引中,创建覆盖索引。例如,查询只需要
- 部分索引:
- 当业务中有特定条件下的频繁查询时,使用部分索引。比如,只对
status
为“active”的文档经常查询,可创建部分索引{status: 1, other_query_field: 1} {partialFilterExpression: {status: "active"}}
。部分索引减少了索引的大小和维护成本,从而对写性能影响较小。
- 当业务中有特定条件下的频繁查询时,使用部分索引。比如,只对
- 平衡读写性能:
- 写操作会更新索引,过多的索引会严重影响写性能。因此要避免创建不必要的索引。定期评估业务需求,删除不再使用的索引。
- 对于写密集型操作,可在写入前暂时禁用索引,写入完成后再重新创建索引,但这种方式可能会在短时间内影响读性能,需谨慎使用。
副本集整体稳定性
- 索引同步:
- 在副本集中,主节点上的索引创建和更新操作会同步到从节点。为确保副本集整体稳定性,要监控索引同步过程。可使用
rs.printReplicationInfo()
和rs.printSlaveReplicationInfo()
命令查看复制信息,确保从节点能及时跟上主节点的索引更新。 - 当副本集成员出现网络故障或重启后重新加入时,要检查索引是否同步完整。可通过比较主从节点上索引的统计信息(如
db.collection.getIndexKeys()
)来确认。
- 在副本集中,主节点上的索引创建和更新操作会同步到从节点。为确保副本集整体稳定性,要监控索引同步过程。可使用
- 负载均衡:
- 合理配置副本集成员的优先级,将读操作尽量分配到从节点上,减轻主节点的压力。可使用
rs.conf()
和rs.reconfig()
命令调整副本集配置,设置不同成员的优先级,如{ "_id" : 0, "host" : "primary.example.com:27017", "priority" : 2 }
,{ "_id" : 1, "host" : "secondary1.example.com:27017", "priority" : 1 }
等。这样高优先级节点更可能成为主节点,而读操作可分布到低优先级的从节点上。
- 合理配置副本集成员的优先级,将读操作尽量分配到从节点上,减轻主节点的压力。可使用
实践中可能遇到的挑战及解决方案
- 索引膨胀:
- 挑战:随着数据量增长,索引占用的磁盘空间可能过大,导致磁盘空间不足,影响系统性能。
- 解决方案:定期对索引进行分析和优化,删除不必要的索引。使用
db.collection.totalIndexSize()
命令查看索引占用的空间大小。考虑使用更紧凑的索引结构,如前缀索引,对于长字符串字段,只取前面几个字符作为索引,减少索引大小,但要注意平衡查询性能。
- 索引维护影响性能:
- 挑战:创建、删除或重建索引时,会消耗大量系统资源,影响读写性能,在高并发场景下尤为明显。
- 解决方案:选择系统负载较低的时间段进行索引维护操作。对于大型集合的索引操作,可采用分批次的方式进行。例如,对于海量数据的集合,可先对部分数据创建索引,逐步完成整个集合的索引创建,避免一次性操作对系统造成过大压力。
- 索引失效:
- 挑战:当查询条件发生变化,或者数据分布改变时,原有的索引可能不再有效,导致查询性能下降。
- 解决方案:定期对查询性能进行监控,使用
explain()
方法分析查询计划,查看索引是否被正确使用。例如,db.collection.find({query_condition}).explain("executionStats")
。如果发现索引未被使用或使用效率低,根据新的业务需求重新评估和调整索引结构。