TTL 索引说“过期时间到了就删”,实际什么时候才真的删?哪些类型的字段会被它删?这篇用 5 秒过期的索引观察实际删除的时刻,再验证字段类型、collMod 和大批量过期。
test> db.getSiblingDB("admin").runCommand({getParameter: 1, ttlMonitorSleepSecs: 1})
{ ttlMonitorSleepSecs: 60, ok: 1 }
已插入 100 个文档,createdAt = 当前时间;索引 expireAfterSeconds=5
文档数变化(距插入的秒数, 剩余): [(59.0, 0)]
TTL 线程的运行时刻(距插入的秒数): [59.0, 119.2];相邻两次相隔 60.2 s
文档在 5 s 时就已过期,实际在 59.0 s 才被删——等到了第一次 TTL 线程运行TTL 索引不是定时器,而是后台线程每 ttlMonitorSleepSecs(默认 60 秒)扫描一轮。5 秒过期的文档等到第一轮运行(59.0 s)才被删,第二轮在 119.2 s。
test> db.adminCommand({setParameter: 1, ttlMonitorSleepSecs: 1})
{ was: 60, ok: 1 }
一小时前的日期等 4 秒之后,还留下: ['iso字符串', 'null', '日期数组(都没过期)', '未来的日期', '毫秒整数', '缺失']只有 BSON 日期(以及日期数组)会过期;字符串形式的日期、毫秒整数、null、缺失字段都不会。日期数组里最早的日期到期,文档就会被删。
三个文档的过期时间分别是 +3 s、+6 s、+9 s;(距插入的秒数, 剩余数): [(3.1, 2), (6.1, 1), (9.2, 0)]
expireAfterSeconds: 0 配合一个存着过期时刻的字段,每个文档在自己指定的时刻之后才会被删。
expireAfterSeconds=3600 时,3 秒后还有 20 个文档(30 秒前创建的还没到 1 小时)
collMod → {expireAfterSeconds_old: 3600, expireAfterSeconds_new: 2}
改成 2 秒后 3.5 秒:剩 0 个
test> db.t4.getIndexes()
[
{
v: 2,
key: { _id: 1 },
name: '_id_',
collation: { locale: 'simple' }
},
{
v: 2,
key: { c: 1 },
name: 'c_1',
expireAfterSeconds: 2,
collation: { locale: 'simple' }
}
]用 collMod 的 index 选项可以直接修改已有 TTL 索引的 expireAfterSeconds,已有文档立即按新规则判断。
test> db.serverStatus().metrics.ttl
{
deletedDocuments: Long('125'),
deletedKeys: Long('251'),
durationMicros: Long('5812'),
examinedDocuments: Long('125'),
examinedKeys: Long('125'),
invalidTTLIndexSkips: Long('0'),
lowPriorityTicketAdmissions: Long('0'),
passes: Long('28'),
queuedForTickets: Long('0'),
subPasses: Long('28'),
ticketAdmissions: Long('111'),
timeProcessingWithTicketsMicros: Long('12477'),
timeQueuedForTicketsMicros: Long('0')
}
test> db.adminCommand({getParameter: 1, ttlMonitorSleepSecs: 1}) // 重启后
{ ttlMonitorSleepSecs: 60, ok: 1 }serverStatus().metrics.ttl 给出 TTL 线程运行了多少轮、删了多少文档;ttlMonitorSleepSecs 可以运行时用 setParameter 调整,重启后恢复默认。
test> db.adminCommand({setParameter: 1, ttlMonitorSleepSecs: 1})
{ was: 60, ok: 1 }
(距开始插入的秒数, 剩余文档数): [(0.5, 200000), (1.6, 0), (1.6, 0)]
TTL 线程运行了 1 轮,共删除 200,000 个文档;从插入完成到删完 1.6 秒20 万个小文档同时过期,一轮就删完了(约 1.6 s,含统计间隔)。