Docs 菜单
Docs 主页
/
MongoDB Manual
/ /

TTL Indexes

在此页面上

  • 创建 TTL 索引
  • 将非 TTL 单字段索引转换为 TTL 索引
  • 更改 TTL 索引的 expireAfterSeconds
  • 行为
  • 限制

注意

如果您为了节省存储成本而删除文档,可以考虑 MongoDB Atlas 中的 Online Archive。Online Archive 可自动将不常访问的数据存档到完全托管的 S3 存储桶,以实现经济高效的数据分层。

TTL 索引是特殊的单字段索引,MongoDB 可以在一定时间后或在特定时钟时间使用这种索引自动从集合中删除文档。数据过期对于某些类型的信息(例如机器生成的事件数据、日志和会话信息)很有用,这些信息仅需要在数据库中保留有限的时间。

警告

创建 TTL 索引后,可能需要一次性删除大量符合条件的文档。如此大的工作负载可能会导致服务器出现性能问题。为了避免此类问题,请计划在非工作时间创建索引,或者在为将来的文档创建索引之前,批量删除符合条件的文档。

要创建 TTL 索引,请使用 createIndex()。指定一个日期类型或包含日期类型值的数组的索引字段。使用 expireAfterSeconds 选项指定 TTL 值(以秒为单位)。

TTL 索引 expireAfterSeconds 值必须介于 02147483647(包含两者)之间。

例如,要在 eventlog 集合的 lastModifiedDate 字段上创建 TTL 值为 3600 秒的 TTL 索引,则在 mongosh 中使用以下操作:

db.eventlog.createIndex(
{ "lastModifiedDate": 1 },
{ expireAfterSeconds: 3600 }
)

从 MongoDB 6.3 开始,可以在时间序列集合上创建部分 TTL 索引。这些索引使用集合 timeField 作为键字段,并且需要在 metaField 上使用部分过滤器表达式

时间序列集合包含可选的 expireAfterSeconds 字段。如果未设置 expireAfterSeconds,则您可以使用带有 partialFilterExpression 的 TTL 索引为与过滤器匹配的文档设置过期期限。如果设置了 expireAfterSeconds,则您也可使用部分 TTL 索引为匹配文档设置较短的过期期限。只能在 metaField 上创建 partialFilterExpression

重要

如果集合的 expireAfterSeconds 值小于部分 TTL 索引的 expireAfterSeconds,则集合会在较短的时间后删除文档,因此 TTL 索引不起作用。

如果时间序列集合包含时间戳在 1970-01-01T00:00:00.000Z 之前或 2038-01-19T03:14:07.000Z 之后为 timeField 的文档,则 TTL“生存时间”功能不会从集合中删除任何文档。

此天气数据时间序列集合会在 24 小时后删除文档:

db.createCollection(
"weather24h",
{
timeseries: {
timeField: "timestamp",
metaField: "sensor",
granularity: "hours"
},
expireAfterSeconds: 86400
}
)

此 TTL 索引会在 1 小时(而不是 24 小时)后从 MongoDB NYC 总部天气传感器中删除文档:

db.eventlog.createIndex(
{ "timestamp": 1 },
{ partialFilterExpression: { "sensor": { $eq: "40.761873, -73.984287" } } },
{ expireAfterSeconds: 3600 } )

从 MongoDB 5.1 开始,您可以将 expireAfterSeconds 选项添加到现有单字段索引。要将非 TTL 单字段索引更改为 TTL 索引,使用 collMod 数据库命令:

db.runCommand({
"collMod": <collName>,
"index": {
"keyPattern": <keyPattern>,
"expireAfterSeconds": <number>
}
})

以下示例将具有模式 { "lastModifiedDate": 1 } 的非 TTL 单字段索引转换为 TTL 索引:

db.runCommand({
"collMod": "tickets",
"index": {
"keyPattern": { "lastModifiedDate": 1 },
"expireAfterSeconds": 100
}
})

要更改 TTL 索引的 expireAfterSeconds 值,请使用 collMod 数据库命令:

db.runCommand({
"collMod": <collName>,
"index": {
"keyPattern": <keyPattern>,
"expireAfterSeconds": <number>
}
})

以下示例更改 tickets 集合上具有模式 { "lastModifiedDate": 1 } 的索引的 expireAfterSeconds 值:

db.runCommand({
"collMod": "tickets",
"index": {
"keyPattern": { "lastModifiedDate": 1 },
"expireAfterSeconds": 100
}
})

重要

在更新 TTL 索引的 expireAfterSeconds 参数之前,请考虑以下几点:

  • 更改 expireAfterSeconds 参数不会触发完全重新生成索引。但是,降低 expireAfterSeconds 值可能会使许多文档符合立即删除条件,并且由于删除操作的增加,可能会导致性能问题。

  • 推荐的方法是在更新 TTL 索引之前手动批量删除文档。这有助于控制对集群的影响。

  • 删除许多文档可能会使存储文件碎片化,从而进一步影响性能。您可能需要在集合上运行 compact 命令或执行初始同步以回收空间并优化存储。

TTL 索引在索引字段值后经过指定的秒数后使文档过期。过期阈值为已编入索引的字段值加上指定的秒数。

如果字段为数组,且索引中有多个日期值,MongoDB 会使用数组中最低(最早)日期值计算过期阈值。

对于时间序列集合,当存储桶中的所有文档都过期时,TTL 索引也会删除该桶中的数据。这等于存储桶的时间戳上限加上 expireAfterSeconds 值。例如,如果存储桶涵盖 2023-03-27T18:29:59Z 之前的数据且 expireAfterSeconds 为 300,则 TTL 2023-03-27T18:34:59Z 索引会在以下项后使存储桶过期。

如果文档中的索引字段不包含一个或多个日期值,则该文档不会过期。

如果文档不包含索引字段,则文档将不会过期。

mongod 中的后台线程会读取索引中的值,并从集合中删除过期文档

TTL 线程执行的正在进行的删除操作出现在 db.currentOp() 输出中。随着 TTL 线程删除文档,metrics.ttl.deletedDocuments 服务器状态指标会增加。

从 MongoDB 6.1 开始:

  • 为了提高效率,MongoDB 可能会批量删除多个文档。

  • explain 命令结果包含用于批量文档删除的新 BATCHED_DELETE 阶段。

如果时间序列集合包含时间戳在 1970-01-01T00:00:00.000Z 之前或 2038-01-19T03:14:07.000Z 之后为 timeField 的文档,则 TTL“生存时间”功能不会从集合中删除任何文档。

TTL 后台删除进程会检查每个 TTL 索引中是否存在过期文档。对于每个 TTL 索引,背景进程会删除文档,直到满足以下条件之一:

  • 该进程从当前索引中删除 50000 个文档。

  • 该进程花费一秒钟从当前索引中删除文档。

  • 所有过期的文档都会从当前索引中删除。

然后,该进程移动到下一个索引。进程遍历每个 TTL 索引一次后,当前子遍历完成,新的子遍历开始检查剩余的过期文档。当 TTL 监控从所有 TTL 索引中删除所有可能的候选文档时,遍历完成。

此外,进程每隔 60 秒就会停止当前的删除循环,以避免在一次大删除上耗费过多时间。发生这种情况时,当前 sub-pass 结束,新的 sub-pass 开始。

遍历和子遍历分别在 metrics.ttl.passesmetrics.ttl.subPasses 服务器状态指标中被跟踪。

索引在主节点上完成构建后,MongoDB 会立即开始删除过期文档或时间序列存储桶。有关索引构建过程的更多信息,请参阅在填充集合上构建索引

TTL 索引不保证过期数据会在过期后立即删除。文档过期时间和 MongoDB 从数据库中删除文档的时间之间可能存在延迟。

删除过期文档的后台任务每 60 秒运行一次。因此,在文档过期和后台任务运行之间的时间段内,文档可能会保留在集合中。MongoDB 在索引完成后 0 到 60 秒开始删除文档。

由于删除操作的持续时间取决于 mongod 实例的工作负载,因此过期数据可能会在后台任务运行之间的 60 秒间隔时间以后存在一段时间。

由 TTL 任务启动的删除操作在前台运行,就像其他删除操作一样。

副本集成员上,TTL 后台线程在成员处于状态时删除文档。当成员处于状态时,TTL 后台线程处于空闲状态。成员复制主成员的删除操作。

TTL 索引支持查询的方式与非 TTL 索引相同。

后退

Sparse