简介
在使用MongoDB时,我们经常需要删除过期或不再需要的数据,以保证数据库的性能和存储效率。MongoDB提供了多种删除数据的方法,包括普通的删除操作(delete)和TTL(Time-To-Live)索引。虽然这两种方法都能从逻辑上删除数据,但它们在磁盘空间管理上的表现却并不相同。
删除操作的基本原理
无论是通过delete命令还是TTL索引,MongoDB删除数据的过程都包括以下几个步骤:
普通删除操作(Delete)
通过delete命令删除文档时,例如:
db.collection.deleteOne({ field: "value" });
被删除的文档从集合中移除,但其占用的磁盘空间并未立即释放。WiredTiger存储引擎会将这些空间标记为可重用,并在将来的写操作中重新使用这些空间。此机制有助于提高写入效率,但可能导致磁盘空间的利用率不理想。
TTL索引删除
TTL索引允许我们为文档设置过期时间,MongoDB会定期扫描集合,并自动删除已过期的文档。创建TTL索引的示例如下:
db.collection.createIndex({ "expireAt": 1 }, { expireAfterSeconds: 0 });
与普通删除操作类似,TTL索引删除的文档也不会立即释放其占用的磁盘空间,而是被标记为可重用。尽管TTL索引自动管理过期数据,避免手动删除的繁琐,但同样无法立即回收磁盘空间。
磁盘碎片由来
在删除MongoDB实例的数据后,这些被删除数据使用的存储空间会被标记为空闲,随后写入的新数据可能会被直接存储到这部分空闲的存储空间中,也可能会先扩展文件的存储空间再存储到文件末尾。上述情况将导致一部分空闲的存储空间不会被使用,这些未被使用的空闲存储空间被称之为磁盘碎片,磁盘碎片越多,磁盘利用率就越低。
查看碎片方法
//无碎片集合
db.tmp0425.stats().wiredTiger["block-manager"]["file bytes available for reuse"]
0
//有碎片集合 18GB
db.el_frequent_visitor_tmp0425.stats().wiredTiger["block-manager"]["file bytes available for reuse"]
20629598208
手动回收磁盘空间的方法
为了确保删除操作后磁盘空间的有效利用,我们可以采用以下几种手动回收磁盘空间的方法:
Compact 命令
compact 命令对指定的集合进行压缩和整理,尝试回收未使用的空间。此操作可能会影响性能,并且在操作期间集合会被锁定。
db.runCommand(
{
compact: <collection name>
}
)
以下是对不同架构,执行操作流程:
1、MongoDB4.4- 7.0 副本集、集群分片
2、MongoDB 4.4以前副本集、集群分片
3、不同版本之间从节点限制
MongoDB 4.4 之前:
MongoDB 4.4:
MongoDB 4.4.17 之后:
4、注意事项
重建索引
ReIndex 命令通过删除集合上的所有索引并重新创建它们,可以在一定程度上帮助减少磁盘碎片。这是因为重新创建索引时,索引数据会被重新写入磁盘,以一种更连续、更有序的方式存储。
db.collection.reIndex();
具体过程
删除现有索引: reIndex 命令首先删除集合上的所有索引。
重新创建索引: 然后重新根据集合中的数据创建这些索引。
通过重新创建索引,索引数据在磁盘上的布局会变得更加连续,从而减少碎片。这可以提高查询性能和存储效率。
注意事项
导出和导入数据
通过 mongodump 和 mongorestore 命令将数据导出到一个文件,然后删除旧数据文件,再将数据重新导入。这个过程确保所有未使用的空间被完全回收。
mongodump --db yourDatabase --out /path/to/backup
mongorestore --drop --db yourDatabase /path/to/backup/yourDatabase
最佳实践
为了优化磁盘空间的使用,我们建议以下最佳实践:
定期维护:定期执行 compact 和重建索引操作,保持数据文件紧凑。
监控和预警:使用 mongostat 和 mongotop 等监控工具设置预警,及时发现和处理磁盘空间不足的问题。
合理配置TTL:根据实际需求设置TTL时间,平衡数据保留时间和存储需求。
通过理解和应用这些磁盘管理机制和最佳实践,我们可以更有效地利用MongoDB的存储资源,确保数据库的高效运行。即使在使用delete和TTL索引删除数据后无法立即释放磁盘空间的情况下,这些方法也能帮助我们最大限度地优化磁盘空间的利用。