Mongo集合20亿数据没有索引,如何清除历史数据?

2024-09-06 19:04:04 浏览数 (2)

背景

某天早上照常进行数据库巡检,发现了MongoDB 集群分片中某个节点的磁盘使用率已经达到了 75%。我立即对该节点的数据库和集合进行了空间分析,发现一个名为 "visitor" 的集合数据量已经达到了 20 多亿条,占用了 260GB 的磁盘空间。我与研发团队讨论后决定清理数据,但需要保留最近半年的数据。然而,我们面临一个尴尬的问题:时间字段没有索引!!!

问题分析

问题主要还是前期产品设计没有考虑历史数据清除策略,任由其数据肆意增长,增长到20亿,时间字段也未添加索引。同时还存在一个严重弊端,这么大的集合未开启分片,导致整个集合数据都存储到同一个shard分片上。shard分片磁盘使用严重倾斜,其他分片只用了25%,当前索引顺序也存在不合理的地方。

集合索引

代码语言:javascript复制
db.getCollection("visitor").createIndex({
    companyId: NumberInt("1"),
    visitorStaticId: NumberInt("1")
}, {
    name: "companyId_1_visitorStaticId_1",
    unique: true
});

解决方案

方案一:添加索引

夜深人静的时候悄悄地把createTime字段后台模式添加索引,综合业务场景(AI客服)、配置(8C16G)、库涉及的业务等,此方案可能会把数据库整崩溃,风险极大,不采用。

方案二:按天迁移数据到新集合

通过写脚本,按照每天的维度,将最近半年的数据分批导入到新表,然后进行rename操作。粗浅地将脚本写完后,进行了简单测试,发现没有索引,查询一天的数据太久,这种方式周期太长,工作量也较大,数据准确性存在较大风险。不采用

代码语言:javascript复制
// 获取当前日期
var currentDate = new Date();


// 获取180天前的日期
var startDate = new Date();
startDate.setDate(startDate.getDate() - 180);


// 将日期转换为毫秒数
var startTime = startDate.getTime();
var endTime = currentDate.getTime();


// 一天的毫秒数
var oneDay = 24 * 60 * 60 * 1000;


// 循环处理每一天的数据
for (var time = startTime; time < endTime; time  = oneDay) {
    // 构造查询条件
    var query = {
        "createTime": {
            "$gte": time,
            "$lt": time   oneDay
        }
    };


    // 查询数据
    var results = db.el_frequent_visitor.find(query);


    // 将查询结果插入到 t2 集合中
    results.forEach(function(doc) {
        db.t2.insert(doc);
    });
}

方案三:使用DTS将数据导入新建集合

步骤一:新建优化好的集合

代码语言:javascript复制
//建新的集合
db.createCollection("visitor_tmp0426");

//修改联合索引顺序
db.getCollection("visitor_tmp0426").createIndex({
    visitorStaticId: NumberInt("1"),
    companyId: NumberInt("1")
}, {
    name: "visitorStaticId_1companyId__1",
    unique: true
});
//创建时间字段索引
db.visitor_tmp0426.createIndex({"createTime":1}, {background: true})
//开启库、集合分片
sh.enableSharding("calldb")
sh.shardCollection("calldb.visitor_tmp0426",{"visitorStaticId":"hashed"})

步骤二:使用DTS进行数据迁移

步骤三:重命名集合

三种方案,最后采用了第三种,这种相对安全、稳定,对数据库影响较小。

注意事项

  • 注意磁盘的使用量
  • DTS速率尽量选用规格较低的
  • 业务低峰操作

大家如果还有更好的建议,踊跃发言,一起看看还有没有更合理的方案

0 人点赞