首页/数据/NoSQL 速查/TTL 索引自动过期文档
MongoDB99 条

TTL 索引自动过期文档

给日期字段建 TTL 索引,后台线程按 expireAfterSeconds 定时清理过期文档;可用 collMod 调整过期时间。

NoSQL 速查数据更新于 2026-10-13

TTL 索引做什么

给日期类型字段建 TTL 索引并指定 expireAfterSeconds,MongoDB 的后台线程就会定期删除「字段值加上该秒数」已经早于当前时间的文档。它把过期清理交给数据库自己完成,适合会话、验证码、临时缓存这类有明确生命周期的数据。

基本信息

创建db.c.createIndex({ expireAt: 1 }, { expireAfterSeconds: 3600 })
调整用 collMod 修改 expireAfterSeconds,不必重建索引
字段要求必须是日期类型,或日期数组(按数组中最早的时间计算)
执行机制后台线程定期轮询,删除是异步的
索引形态必须是单字段索引,复合索引不支持 TTL 选项

典型使用场景

  • 会话与登录令牌到期清理
  • 短信验证码、一次性令牌过期删除
  • 临时缓存与中间状态数据自动回收
  • 日志或审计记录按保留期滚动清理
  • 事件去重表:只保留最近一段时间的键

创建与调整

创建与调整
// 创建 TTL 索引:字段时间点之后 3600 秒过期
 db.sessions.createIndex({ expireAt: 1 }, { expireAfterSeconds: 3600 })

// 调整过期时间:用 collMod,不需要重建索引
 db.runCommand({
   collMod: "sessions",
   index: { keyPattern: { expireAt: 1 }, expireAfterSeconds: 7200 }
 })

// 查看索引配置,确认 TTL 是否生效
 db.sessions.getIndexes()

// 插入一条 10 秒后过期的文档
 db.sessions.insertOne({ _id: "s1", expireAt: new Date(Date.now() + 10 * 1000) })

过期行为读法

情况行为注意
字段值是日期按字段值加 expireAfterSeconds 计算过期到点后由后台线程删除
字段不是日期或字段缺失该文档永不过期类型写错时会静默残留
删除时机后台线程定期轮询不保证到点即删
同字段已有普通索引创建 TTL 索引会报选项冲突需先删除旧索引再重建
TTL 的删除是后台异步过程,不保证在过期时间点被立刻清除;对时效敏感的查询必须在查询条件里再过滤一次过期时间,不能只依赖索引删除。
调整 expireAfterSeconds 用 collMod 即可;但把已有普通索引改造成 TTL 索引必须先删除再重建,重建期间该字段会失去索引保护,操作前要评估查询影响。

易错点

  • 删除不保证到点即删,依赖后台线程与实例负载,对精确性敏感的场景必须在查询侧再过滤一次
  • 把 TTL 建在非日期字段上(如字符串时间或毫秒时间戳数值),文档永远不会过期,只会静默累积
  • 在已有普通索引的同一字段上直接创建 TTL 索引会报选项冲突,必须先删旧索引再重建,期间字段失去索引
  • 误以为复合索引也能带 TTL:复合索引不支持该选项,写了也不生效,需要拆出单独的日期字段建单字段 TTL 索引

数据来源与参考

  • MongoDB Manual: TTL Indexes
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌