MST

星途 面试题库

面试题:MongoDB索引对象和数组在高并发读写场景下的优化

在一个高并发读写的应用场景中,MongoDB集合中的文档包含复杂的对象和数组结构。读操作主要是基于多个字段(包括对象内字段和数组内元素)的组合条件查询,写操作包括插入新文档、更新对象或数组中的值。请阐述如何从索引优化的角度,平衡读写性能,减少锁争用,提高系统整体吞吐量,并给出具体的索引优化建议和可能涉及的相关配置或参数。
29.7万 热度难度
数据库MongoDB

知识考点

AI 面试

面试题答案

一键面试

索引优化策略

  1. 复合索引
    • 对于基于多个字段的组合条件查询,创建复合索引。例如,如果经常按field1field2field3组合查询,创建索引db.collection.createIndex({field1: 1, field2: 1, field3: 1})。索引字段顺序很重要,应将选择性高(即值的唯一性高)的字段放在前面,以提高查询效率。
  2. 覆盖索引
    • 尽量使用覆盖索引,即查询所需要的所有字段都包含在索引中。这样查询时MongoDB可以直接从索引中获取数据,而不需要回表操作,减少磁盘I/O。例如,如果查询field1field2,且field3的值不关心,可以创建索引db.collection.createIndex({field1: 1, field2: 1}),然后查询db.collection.find({field1: value1, field2: value2}, {field1: 1, field2: 1, _id: 0})。这里_id默认会在索引中,如果不需要显示返回,可设置为0。
  3. 数组索引
    • 对于数组内元素的查询,创建数组索引。例如,如果文档中有数组arrayField,且经常查询数组中包含某个值的文档,可创建索引db.collection.createIndex({"arrayField": 1})。对于嵌套数组或需要更复杂查询的数组结构,可能需要使用多键索引等更高级的技术。
  4. 部分索引
    • 当写操作频繁且某些查询只针对部分数据时,使用部分索引。例如,只对status"active"的文档进行特定查询,可创建部分索引db.collection.createIndex({field1: 1}, {partialFilterExpression: {status: "active"}})。这样可以减少索引维护成本,提高写性能,同时不影响特定查询的读性能。

平衡读写性能与减少锁争用

  1. 读写分离
    • 利用MongoDB的副本集功能,将读操作分配到从节点。在应用程序配置中,设置读偏好为secondaryPreferredsecondary,这样大部分读操作会从从节点获取数据,减轻主节点的压力,减少读写锁争用。例如在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);
    
  2. 合理使用索引
    • 避免创建过多不必要的索引,因为每个索引都需要额外的磁盘空间和维护成本。过多索引会增加写操作时的锁争用,因为每次写操作都可能需要更新多个索引。定期评估索引的使用情况,删除不再使用的索引,可使用db.collection.totalIndexSize()查看索引占用空间,以及db.collection.find().explain("executionStats").queryPlanner.winningPlan.inputStage.indexName查看查询使用的索引。

相关配置与参数

  1. 副本集配置
    • 在副本集配置文件中,可以调整成员节点的优先级,例如:
    {
        "_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
            }
        ]
    }
    
    • 优先级高的节点更有可能成为主节点,可根据读写负载合理分配优先级。
  2. MongoDB配置文件
    • mongod.conf中,可以调整storage.wiredTiger.engineConfig.cacheSizeGB参数,设置WiredTiger存储引擎的缓存大小。适当增大缓存可以提高读写性能,因为更多的数据和索引可以缓存在内存中,减少磁盘I/O。例如:
    storage:
        wiredTiger:
            engineConfig:
                cacheSizeGB: 2
    
    • 还可以调整operationProfiling相关参数来监控和分析读写操作性能,例如:
    operationProfiling:
        mode: "slowOp"
        slowOpThresholdMs: 100
    
    • 这里设置了只记录执行时间超过100毫秒的慢操作,通过分析这些慢操作来进一步优化索引和查询。