文档菜单
文档首页
/
MongoDB 手册
/ /

TTL 索引

本页内容

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

注意

如果您正在删除文档以节省存储成本,请考虑在线归档,它位于MongoDB Atlas中。在线归档会自动将不常访问的数据存档到全管理的S3桶中,以实现成本效益的数据分层。

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

警告

创建TTL索引后,它可能一次要删除大量符合资格的文档。这种大量工作可能会在服务器上引起性能问题。为了避免这些问题,请计划在非高峰时段创建索引,或在创建索引之前分批删除符合资格的文档。

要创建一个TTL索引,请使用createIndex()方法。[点击此处查看详情](/docs/manual/reference/method/db.collection.createIndex/#mongodb-method-db.collection.createIndex)。指定一个索引字段,该字段可以是日期类型或包含日期类型值的数组。使用expireAfterSeconds选项来指定以秒为单位的TTL值。

TTL索引的expireAfterSeconds值必须在02147483647之间(包含)。

例如,要在eventlog集合的lastModifiedDate字段上创建一个TTL值为3600秒的TTL索引,请使用以下在mongosh中进行的操作。[点击此处查看详情](https://mongodb.ac.cn/docs/mongodb-shell/#mongodb-binary-bin.mongosh)

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

从MongoDB 6.3版本开始,您可以为时间序列集合创建部分TTL索引。[点击此处查看详情](/docs/manual/core/timeseries-collections/#std-label-manual-timeseries-landing)。这些索引使用集合的timeField作为键字段,并在metaField上需要部分过滤表达式。

时间序列集合包含一个可选的expireAfterSeconds字段。如果您未设置expireAfterSeconds,则具有部分过滤表达式的TTL索引可让您为与过滤器匹配的文档设置过期期限。如果您设置了expireAfterSeconds,则部分TTL索引可让您为匹配的文档设置不同的、较短的过期期限。您只能在metaField上创建部分过滤表达式。

重要

如果集合的expireAfterSeconds值小于部分TTL索引的expireAfterSeconds,则集合在较短的时间内删除文档,因此TTL索引无效。

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

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

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

此TTL索引在1小时后从MongoDB纽约总部天气传感器中删除文档,而不是24小时

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命令或执行一个Initial Sync来回收空间并优化存储。

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 阶段,用于批量文档删除。

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

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

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

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

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

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

此外,该过程每60秒停止当前删除循环,以防止花费太多时间在单个大删除上。当发生这种情况时,当前子遍历结束,并开始新的子遍历。

遍历和子遍历分别记录在metrics.ttl.passesmetrics.ttl.subPasses 服务器状态度量中。

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

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

删除过期文档的背景任务每60秒运行一次。因此,文档可能在文档过期与后台任务运行之间的期间内存在于集合中。MongoDB在索引完成后0到60秒内开始删除文档。

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

TTL任务发起的删除操作与其他删除一样,在后台运行。

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

TTL索引支持查询,与非TTL索引相同。

当mongod在单机模式下运行且system.local.replset集合包含数据时,TTL监视器将停止。如果您将副本集节点从副本集移除并作为单机运行,则TTL监视器将被禁用。

  • TTL索引是单字段索引。复合索引不支持TTL并忽略expireAfterSeconds选项。

  • id字段不支持TTL索引。

  • 从MongoDB 7.0开始,您可以在时间序列集合的metaField上创建部分TTL索引。在早期MongoDB版本中,您只能为时间序列集合的timeField创建TTL索引。

  • 您不能使用 createIndex() 来更改现有索引中 expireAfterSeconds 的值。相反,请使用 collMod 数据库命令。有关详细信息,请参阅 更改 TTL 索引的 expireAfterSeconds 值。

  • 如果一个字段的非 TTL 单字段索引已经存在,则不能在该字段上创建 TTL 索引,因为不能创建具有相同键规范但选项不同的索引。要 将非 TTL 单字段索引更改为 TTL 索引,请使用 collMod 数据库命令。

返回

稀疏