← 返回题目列表

MongoDB 的 TTL 索引是什么?适合哪些场景?

高频 中等 第 6 / 31 题 更新于 2026/07/29
MongoDBTTL索引过期删除索引

简化版

TTL 索引用来让 MongoDB 自动删除过期文档,常用于会话、验证码、临时 token、日志和短期事件数据。它依赖日期字段和后台清理线程,删除不是毫秒级准时触发,不能用于强实时过期业务。

详细版

TTL 索引通常建在单个日期字段上,并通过 expireAfterSeconds 指定保留时间:

db.sessions.createIndex(
  { expiresAt: 1 },
  { expireAfterSeconds: 0 }
)

expiresAt 早于当前时间时,文档会被后台任务删除。面试要强调 3 点:TTL 删除是异步的;字段类型要是日期或日期数组;适合清理冷数据,不适合作为严格定时任务或支付超时这种强一致触发器。

完整版教学

一、TTL 索引解决自动清理问题

很多业务数据天然有生命周期:登录 session 30 分钟过期,验证码 5 分钟有效,接口幂等 token 24 小时保留,埋点日志只保留 7 天。

如果完全靠应用定时任务删除,容易出现任务漏跑、批量删除压力大、多个服务重复清理等问题。TTL 索引把“到期删除”交给 MongoDB 后台机制处理。

db.login_codes.createIndex(
  { createdAt: 1 },
  { expireAfterSeconds: 300 }
)

这表示文档的 createdAt 超过 300 秒后,会被后台清理。

记忆钩子:TTL 索引是数据库内置的“保质期标签”,适合自动清理,不适合准点触发。

二、TTL 有两种常见建模方式

第一种是“创建时间 + 保留秒数”:

db.events.createIndex(
  { createdAt: 1 },
  { expireAfterSeconds: 7 * 24 * 3600 }
)

第二种是“到期时间 + 0 秒”:

db.sessions.createIndex(
  { expiresAt: 1 },
  { expireAfterSeconds: 0 }
)
方式字段含义适合场景
createdAt + N从创建时间开始保留 N 秒日志、埋点、验证码
expiresAt + 0到具体时间点过期session、token、优惠券锁定

第二种更灵活,因为每个文档可以有不同过期时间。

三、TTL 删除不是准实时

TTL 索引由后台任务周期性扫描并删除过期文档,因此过期文档可能会多存活一小段时间。

这点在面试里很关键。TTL 适合“最终会被清理”的场景,不适合“到点必须立即执行动作”的场景。

例如支付订单 15 分钟未支付要关闭,不能只依赖 TTL 删除订单。更合理的是状态机加定时扫描、延迟消息或任务调度,TTL 最多用于清理临时锁或过期辅助数据。

验证码过期 -> TTL 可以
支付订单关闭 -> 业务任务处理状态,TTL 不做主流程
审计日志保留 180 天 -> TTL 可以

四、TTL 字段类型和索引限制要记住

TTL 索引通常要求字段是日期类型,或者包含日期值的数组。字段不存在或类型不对,文档不会按预期删除。

// 推荐
{ createdAt: ISODate("2026-07-29T10:00:00Z") }

// 风险:字符串不是日期类型
{ createdAt: "2026-07-29 10:00:00" }

TTL 索引一般是单字段索引,不是拿来替代复合查询索引的。不要指望一个 TTL 索引同时解决过期删除和复杂查询排序。

如果业务既要按 userId 查询,又要过期删除,通常需要分别设计查询索引和 TTL 索引。

五、大批量过期会带来删除压力

如果很多文档在同一时间过期,后台删除会造成 I/O 和复制压力。比如每天 0 点让 1000 万条文档同时过期,会产生大量删除操作。

更平滑的方式是让过期时间分散,或者按时间分桶建集合,老集合整体下线。

数据量过期分布建议
均匀TTL 索引即可
集中分散过期时间或削峰
极大按天保留考虑按日期集合或归档

TTL 删除本身也会进入复制流程,所以 Secondary 同样要应用删除操作。

六、TTL 与业务状态要分层

TTL 删除的是文档,不是业务事件处理器。如果删除本身会触发后续动作,比如退款、通知、释放库存,那就不能只靠 TTL。

更可靠的设计是:

业务状态表:记录订单、锁定、超时状态
调度系统:到期扫描或延迟触发
TTL 数据:清理临时 token、验证码、幂等记录

也就是说,TTL 适合作为数据生命周期管理工具,不适合作为核心业务流程编排工具。

七、常见误区与追问

  • 误区:TTL 到期会立刻删除。 TTL 删除由后台任务异步执行,可能存在延迟。
  • 误区:TTL 可以替代订单超时任务。 订单关闭涉及状态流转和副作用,应该由业务任务保证,TTL 只适合清理辅助数据。
  • 误区:日期字符串也能正常 TTL。 TTL 字段应使用日期类型,字符串通常不会按预期过期。
  • 追问:expireAfterSeconds: 0 表示什么? 表示直接使用字段里的到期时间,字段时间早于当前时间就可被清理。
  • 追问:大批量 TTL 删除有什么风险? 会带来磁盘、复制和锁竞争压力,可能造成复制延迟。
  • 追问:TTL 索引能不能同时优化查询? 不建议依赖它解决复杂查询,查询索引和生命周期索引应分别设计。

八、加强记忆

TTL 索引要记住“日期字段、后台删除、最终清理”。它用 expireAfterSeconds 给文档生命周期兜底,适合验证码、session、临时 token、日志等短生命周期数据;但删除不是准实时,字段类型必须正确,大批量集中删除会有压力。业务状态到期要靠任务或消息驱动,TTL 负责清理数据,不负责推动复杂业务流程。