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 索引必须先删除再重建,重建期间该字段会失去索引保护,操作前要评估查询影响。