mongodb双写解决TTL索引失效

症状

  • 生产环境某个 mongodb 超大表(约6000w笔),配置了 TTL 索引(保留30天),但历史数据并没有自动过期删除

分析

  • 登录该mongo实例,发现该表TTL索引并非建在date类型上,由于该表访问比较频繁且数据量太大,直接修改字段类型并不推荐。以下是针对不同日期类型的测试方案:
use db1;
db.createCollection("log_events");

//.以下满足ttl索引对date类型的要求
db.log_events.insert({"user_name":"aaa", "created_at":new Date(), "log_message":"Success"});
db.log_events.insert({"user_name":"aaa", "created_at":new Date('Jun 26, 2025 11:20:07'), "log_message":"Success"});

//.以下不满足ttl索引对date类型的要求
db.log_events.insert({"user_name":"aaa", "created_at":1748402407, "log_message":"Failed"});
db.log_events.insert({"user_name":"aaa", "created_at":"2025-05-26 11:20:07", "log_message":"Failed"});

// 使用 collMod 修改 expireAfterSeconds的属性
// db.runCommand({collMod: "log_events", index: { keyPattern: { created_at: 1 }, expireAfterSeconds: 60}});

//.创建ttl索引
db.log_events.createIndex({"created_at":1}, {expireAfterSeconds:60*60*24*7*30});
db.log_events.find();

解决方案

  • 第1步,新增一个新表并对date类型字段创建配置TTL索引,比如 30 天
//.创建新表
use db1;
db.createCollection("log_events_new");

//.告知开发同事,写入的日期务必为date类型
db.log_events_new.insert({"user_name":"aaa", "created_at":new Date(), "log_message":"Success"});

//.保留30天的ttl索引
db.log_events_new.createIndex({"created_at":1}, {expireAfterSeconds:60*60*24*7*30});
  • 第2步,择机发版配置双写方案(写入的日期务必为date类型),双写持续的时间务必覆盖ttl索引的时效,比如 40 天
  • 第3步,择机对这2张表执行 rename 将名字互换,并发版取消双写方案
use db1;
db.log_events.renameCollection("log_events_2025");
db.log_events_new.renameCollection("log_events");
db.log_events_2025.renameCollection("log_events_new");
Copyright © www.sqlfans.cn 2021 - 2026 All Right Reserved更新时间: 2026-09-02 17:19:16

results matching ""

    No results matching ""