使用 TTL 索引定期清理 MongoDB 中某个集合的数据

JAVA herman 636浏览
公告:“业余草”微信公众号提供免费CSDN下载服务(只下Java资源),关注业余草微信公众号,添加作者微信:xttblog,发送下载链接帮助你免费下载!
本博客日IP超过1800,PV 2600 左右,急需赞助商。
极客时间所有课程通过我的二维码购买后返现24元微信红包,请加博主新的微信号:xttblog,之前的微信号好友位已满,备注:返现
所有面试题(java、前端、数据库、springboot等)一网打尽,请关注文末小程序
视频教程免费领

最近我在学习 MongoDB,在 MongoDB 中文社区里看到了一个投票最多的帖子。投票最多的也就意味着用的人多,遇到这个需求,有这个需要的人也多。所以,我就针对性的重点研究了一下。把如何定期清理 mongo 中某个集合的数据经验分享给大家!

要实现定时清理过期数据,就需要创建 MongoDB 的 TTL(Time To Live) 索引。创建该索引后,MongoDB 数据库将在后台起一个线程,每 60s 触发一次,检查 MongoDB 中的数据,检查过期数据,并执行具体的动作。

下面我们一起看一个案例:

db.xttblog.createIndex({"createDate":1},{expireAfterSeconds:3600});

解释一下,xttblog 是集合的名字。createIndex 是创建索引,3.0 以前的版本创建索引可以使用 ensureIndex,从 MongoDB 3.0开始 ensureIndex 被废弃,今后都仅仅是 db.collection.createIndex 的一个别名。createDate 是集合 xttblog 中的字段,TTL 索引最终就是创建在该字段上,为 Date 日期格式。expireAfterSeconds 是过期时间,根据字段的名称就可以看出来,它是多少秒后过期。

TTL 索引是 MongoDB 中的一种特殊的索引, 可以支持文档在一定时间之后自动过期删除,目前 TTL 索引只能在单字段上建立,并且字段类型必须是 date 类型或者包含有 date 类型的数组(如果数组中包含多个 date 类型字段,则取最早时间为过期时间)。更多资料请参考官方说明:https://docs.mongodb.com/v3.2/core/index-ttl/。从这里也可以看出,TTL 是 MongoDB 3.2 版本以后才支持的。

查看索引:

db.xttblog.getIndexes();

索引信息如下:

[
	{
        "v" : 1,
        "key" : {
                "_id" : 1
        },
        "name" : "_id_",
        "ns" : "tt.t1"
	},
	{
        "v" : 1,
        "key" : {
                "createDate" : 1
        },
        "name" : "createDate_1",
        "ns" : "tt.t1",
        "expireAfterSeconds" : 3600
	}
]

如果想更改过期时间 expireAfterSeconds,可以使用 collMod 方法,要不然你只能只用 dropIndex(),然后再用 createIndex() 方法重建索引了。这种重建索引的方法是非常不推荐的,因为在亿级数据量下是很恐怖的。

db.runCommand( {collMod: "xttblog", --- 集合名
	index: { keyPattern: { createDate: 1 }, --- createDate 为具有 TTL 索引的字段名
		expireAfterSeconds: 7200 --- 修改后的过期时间(秒)
	}}
)

TTL 索引的缺点也很大,比如只支持单列索引、每 60s 检查一次、修改索引影响大等缺点。如果白天业务比较忙,是吧,TTL 索引定时的去删除数据,对应上亿的数据量性能影响是非常大的。所以定时清理一般要放在夜晚时间,业务量较少的情况下进行。

db.xttblog.createIndex( { "expireTime": 1 }, ---字段名称
	{ expireAfterSeconds: 0 }  ---过期时间(单位秒)
)
// 业余草:www.xttblog.com  
db.xttblog.insert( {
  "expireTime": new Date('Jan 22, 2018 23:00:00'), --- 此文档将在2018-1-22的23点自动删除
  "logEvent": 2,
  "logMessage": "Success!"} 
)

上面的做法就可以在指定时间自动删除数据了。

TTL 索引虽然好,但也有很多限制条件。

  • TTL 索引是单字段索引,混合索引不支持 TTL,并且也会忽略 expireAfterSeconds 属性
  • 在 _id 主键上不能建立 TTL 索引
  • 在 capped collection 中不能建立 TTL 索引,因为 MongoDB 不能从 capped collection 中删除文档
  • 不能使用 createIndex() 去更改已经存在的 TTL 索引的 expireAfterSeconds 值,如果想更改 expireAfterSeconds,可以使用 collMod 命令,否则你只能删除索引,然后重建了
  • 不能在已有索引的字段上再创建 TTL 索引了,如果你想把非 TTL 索引改为 TTL 索引,那就只能删除重建索引了

如何定期清理 mongo 中某个集合的数据

有人测试过 TTL 索引在亿级别集合中删除 140 万过期数据的消耗。删除操作整个过程在 90 秒左右完成;CPU 最高占用 90%,平均在 50%,内存占用 3G。测试配置,OS:Vm虚拟机,CPU: 4 核,内存:8G。

业余草公众号

最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加QQ1群:135430763(2000人群已满),QQ2群:454796847(已满),QQ3群:187424846(已满)。QQ群进群密码:xttblog,想加微信群的朋友,之前的微信号好友已满,请加博主新的微信号:xttblog,备注:“xttblog”,添加博主微信拉你进群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作可添加助理微信进行沟通!

本文原文出处:业余草: » 使用 TTL 索引定期清理 MongoDB 中某个集合的数据