我们使用Mongo时,经常会存一些不太重要的事件、日志等数据,这部分数据有时效性,一般是有问题时辅助排查使用,太久以前的历史数据就没什么价值了,但是不做特殊处理的话,数据量会越来越大,这里就用到了TTL索引,类似于redis给key设置过期时间。详见官方文档:TTL Indexes - 数据库手册 - MongoDB Docs
TTL (Time To Live, 有生命周期的) 索引是特殊单字段索引,MongoDB可以用来在一定时间后自动从集合中删除文档的特殊索引。 这对于某些类型的数据非常好,例如机器生成的事件数据,日志和会话信息,这些信息只需要在数据库中保留一段时间。
创建 TTL 索引,只需要在使用 db.collection.createIndex() 方法,对字段值为日期或者包含日期的数组设置 expireAfterSeconds 选项即可。TTL 索引 expireAfterSeconds 值必须介于0和2147483647(包含两者)之间。
1、如果字段是一个数组,并有多个日期值时,MongoDB使用最低(即最早)日期值来计算失效阈值。
2、如果字段不是日期类型也不是一个包含日期的数组类型那么文档就永远不会过期。
3、如果一个文档不包含索引字段,该文档也不会到期。
sql
// 创建一个 TTL 索引
db.eventlog.createIndex( { "lastModifiedDate": 1 }, { expireAfterSeconds: 3600 } )
**注意**:创建 TTL 索引后,可能需要一次性删除大量符合条件的文档。如此大的工作负载可能会导致服务器出现性能问题。为了避免此类问题,请计划在非工作时间创建索引,或者在为将来的文档创建索引之前,批量删除符合条件的文档。
要将非 TTL 单字段索引更改为 TTL 索引或更改TTL索引的expireAfterSeconds值,使用collMod数据库命令:
sql
db.runCommand({
"collMod": <collName>,
"index": {
"keyPattern": <keyPattern>,
"expireAfterSeconds": <number>
}
})
数据过期
TTL 索引在索引字段值后经过指定的秒数后使文档过期。过期阈值为已编入索引的字段值加上指定的秒数。
如果字段为数组,且索引中有多个日期值,MongoDB 会使用数组中最低(最早)日期值计算过期阈值。
如果文档中的索引字段不包含一个或多个日期值,则该文档不会过期。
如果文档不包含索引字段,则文档将不会过期。
删除操作
过期数据的删除工作是由 mongod 后台线程来执行,每60秒进行一次。
索引在主节点上完成构建后,MongoDB 会立即开始删除过期文档或时间序列存储桶。
TTL 索引不保证过期数据会在过期后立即删除。文档过期时间和 MongoDB 从数据库中删除文档的时间之间可能存在延迟。
在副本集成员上,TTL 后台线程只在成员处于主状态时删除文档。当成员处于从状态时,TTL 后台线程处于空闲状态。从成员复制主成员的删除操作。
**注意**TTL 删除过程是一个单线程后台任务,这意味着 TTL 删除不是并发的,并且在高工作负载或处理大量过期文档时可能需要更长时间。
索引区别
对于查询而言,TTL 索引和其他索引没有区别。
TTL索引有哪些限制
TTL 索引是单字段索引。复合索引不支持 TTL,并且会忽略 expireAfterSeconds 选项。
_id 字段不支持减 TTL 索引。
不能使用 createIndex() 更改现有索引的 expireAfterSeconds 值。请使用 collMod 数据库命令。否则,改变现有索引的选项的值,你必须删除索引,重新创建。
如果某个字段已存在非 TTL 单字段索引,则无法对同一字段创建 TTL 索引,因为无法创建具有相同键规范且仅选项不同的索引。要将非 TTL 单字段索引更改为 TTL 索引,请使用 collMod 数据库命令。