奇葩的业务设计,奇葩的MongoDB删除清理程序
❝开头还是介绍一下群,如果感兴趣PolarDB ,MongoDB ,MySQL ,PostgreSQL ,Redis, OceanBase, Sql Server等有问题,有需求都可以加群群内有各大数据库行业大咖,可以解决你的问题。加群请联系 liuaustin3 ,(共3300人左右 1 + 2 + 3 + 4 +5 + 6 + 7 + 8 +9)(1 2 3 4 5 6 7群均已爆满,开8群近400 9群 300+,开10群PolarDB专业学习群100+)
最近活多,这不来事了,MongoDB之前提到过的,线下单机的开发自己装的,记录日志的。后来迁移到云上了,程序不能动只能继续使用MongoDB4.4.
现在抛给我一个新的问题,里面有一个库,库里面有
[direct: primary] lo> db.getCollectionNames().length;
19521
接近2万个collections,千万不要谴责我,这个库比我来这个单位早,那都是可爱的 programer,你看我都没有叫他developer。一群无知的人,mognodb单库存多少collections合适。
MongoDB 的存储引擎 WiredTiger 会为每个打开的集合和索引分配内存,每一个 Collection 和每一个 Index 都是一个文件,打开 2 万个集合意味着系统需要维护海量的文件句柄和元数据,数据库需要频繁地换入/换出这些集合的元数据,导致缓存命中率下降,直接拖慢整体读写速度。
同时每个collection都建立了2-3个索引的话,那一个数据库要有4-6万个索引,mongodb处理数据的方法是将索引驻入内存,才能保存高性能。所以这样的设计会导致消耗非常多的内存,然后启动数据库的时间时mongodb 要验证和扫描所有的元数据,开机会非常的慢,后面我说不下去了,读者你来帮我说说,就这群开发人员是都有有意思。
MongoDB是开发者数据库,不是开玩笑数据库。
我先说一下这个库的设计,这里每一个collecion都是一个客户的操作信息,在这样的设计中,会造成MongoDB非常不愿意看到的,一个逻辑库有大量的collecions。
有多少
[direct: primary] log> db.getCollectionInfos().length
19544
[direct: primary] log>
在一个MongoDB 的库里将近有20000个collections,我们现在需要针对每个collections 里面的日期数据超过最近3个月的数据进行清理。
同时在看我的简易清理程序中,你应该会问我,为什么没有索引,这里说过他的设计是来一个客户,会增加一个collection,所以这个逻辑库会一直增加collection。
同时还有一个问题,非常的奇葩,不能加主键以外的索引,这一个个表只有一个objectID,写到这里一定有人问,为什么不加索引。
1 这些表有的可能只有几行数据,有的会有很多行数据几万,十几万不等,当然也有的有几百万。
2 磁盘空间的问题,如果每个都加索引那么磁盘空间必然要暴涨。
基于这个问题,所以写程序删除我这边也只能如此
node.js 22.04 写的一个简易,但针对这个场景比较万能的清理数据的程序,只要opedate是三个月之前的数据,就直接删除。
const { MongoClient } = require('mongodb');
const uri = "mongodb://地址";
const client = new MongoClient(uri);
async functiondeleteOldLogs() {
try {
await client.connect();
console.log("Connected to the database");
const database = client.db('logs');
const collections = await database.listCollections().toArray();
const deleteBeforeDate = new Date();
deleteBeforeDate.setMonth(deleteBeforeDate.getMonth() - 3);
const logFile = "deleteLogs.txt";
const logFileStream = require('fs').createWriteStream(logFile, { flags: 'a' });
for (const collection of collections) {
const cursor = database.collection(collection.name).find();
await cursor.forEach(async (doc) => {
const opedate = new Date(doc.opedate);
if (opedate < deleteBeforeDate) {
const deletionCommand = await database.collection(collection.name).deleteOne({ _id: doc._id });
const logMessage = `Deleting document from collection ${collection.name} with opedate: ${doc.opedate}\n`;
console.log(logMessage);
logFileStream.write(logMessage);
console.log(deletionCommand);
}
});
}
logFileStream.close();
} catch (error) {
console.error("Failed to delete old logs:", error);
} finally {
await client.close();
console.log("Connection closed");
}
}
目前这个程序已经运行了1年,除了运行的时候,CPU和内存会上升以外,其他均没有太大的问题。
写到这里,有人会问,为什么不加索引的,看上面已经写了为什么,另外还有一个问题不加索引是,每个collections因为是基于客户进行划分,最大的表的量也不是太多,否则如果一个表几个亿的情况,那就完全不可以了。
另外还有一个问题,为什么不设置成,deleteMany,这里需要提醒,因为我并不知道业务的发展的变化,如果是deleteMany 会导致某些表一次删除大量的数据,导致大事务的问题,给MongoDB的日志oplog日志传输导致问题,
for (const collection of collections) {
const deletionCommand = await database.collection(collection.name).deleteMany({ opedate: { $lt: deleteBeforeDate } });
const logMessage = `Deleted ${deletionCommand.deletedCount} documents from collection ${collection.name} with opedate before ${deleteBeforeDate}\n`;
console.log(logMessage);
logFileStream.write(logMessage);
写到这里,这样的设计的确令人崩溃,但这世界上就有这样的设计,且到你手里进行维护,怎样,不还是得干。
这里也有一个想法,可以进行一次查询 确定object_ID的临界3个月的主键,然后凡是小于次主键的都可以进行删除。
但那样设计,程序的逻辑会比较麻烦,目前这样做也适合这个奇葩的系统。
人生勿求尽善尽美,谁不是毛病一堆,搭肩勾背的活着吧!!
和架构师沟通那种“一坨”的系统,推荐只能是OceanBase,Why ?
OceanBase Hybrid search 能力测试,平换MySQL的好选择
写了3750万字的我,在2000字的OB白皮书上了一课--记 《OceanBase 社区版在泛互场景的应用案例研究
OceanBase 6大学习法--OBCA视频学习总结第六章
OceanBase 6大学习法--OBCA视频学习总结第五章--索引与表设计
OceanBase 6大学习法--OBCA视频学习总结第五章--开发与库表设计
OceanBase 6大学习法--OBCA视频学习总结第四章 --数据库安装
OceanBase 6大学习法--OBCA视频学习总结第三章--数据库引擎
OceanBase 架构学习--OB上手视频学习总结第二章 (OBCA)
OceanBase 6大学习法--OB上手视频学习总结第一章
没有谁是垮掉的一代--记 第四届 OceanBase 数据库大赛
跟我学OceanBase4.0 --阅读白皮书 (OB分布式优化哪里了提高了速度)
跟我学OceanBase4.0 --阅读白皮书 (4.0优化的核心点是什么)
跟我学OceanBase4.0 --阅读白皮书 (0.5-4.0的架构与之前架构特点)
跟我学OceanBase4.0 --阅读白皮书 (旧的概念害死人呀,更新知识和理念)
OceanBase 学习记录-- 建立MySQL租户,像用MySQL一样使用OB
“合体吧兄弟们!”——从浪浪山小妖怪看OceanBase国产芯片优化《OceanBase “重如尘埃”之歌》
MongoDB “升级项目” 大型连续剧(3)-- 自动校对代码与注意事项
MongoDB “升级项目” 大型连续剧(2)-- 到底谁是"der"
MongoDB “升级项目” 大型连续剧(1)-- 可“生”可不升
MongoDB 大俗大雅,上来问分片真三俗 -- 4 分什么分
MongoDB 大俗大雅,高端知识讲“庸俗” --3 奇葩数据更新方法
MongoDB 大俗大雅,高端的知识讲“通俗” -- 2 嵌套和引用
MongoDB 大俗大雅,高端的知识讲“低俗” -- 1 什么叫多模
MongoDB 合作考试报销活动 贴附属,MongoDB基础知识速通
MongoDB 使用网上妙招,直接DOWN机---清理表碎片导致的灾祸 (送书活动结束)
MongoDB 2023年度纽约 MongoDB 年度大会话题 -- MongoDB 数据模式与建模
MongoDB 麻烦专业点,不懂可以问,别这么用行吗 ! --TTL
免费PolarDB云原生课程,听课“争”礼品,重塑云上知识,提高专业能力
非“厂商广告”的PolarDB课程:用户共创的新式学习范本--7位同学获奖PolarDB学习之星
“当复杂的SQL不再需要特别的优化”,邪修研究PolarDB for PG 列式索引加速复杂SQL运行
“PostgreSQL” 高性能主从强一致读写分离,我行,你没戏!
POLARDB 添加字段 “卡” 住---这锅Polar不背
PolarDB 版本差异分析--外人不知道的秘密(谁是绵羊,谁是怪兽)
PolarDB 答题拿-- 飞刀总的书、同款卫衣、T恤,来自杭州的Package(活动结束了)
PolarDB for MySQL 三大核心之一POLARFS 今天扒开它--- 嘛是火
PostgreSQL 新版本就一定好--由培训现象让我做的实验
说我PG Freezing Boom 讲的一般的那个同学,专帖给你,看看这次可满意
PostgreSQL 无服务 Neon and Aurora 新技术下的新经济模式 (翻译)
“PostgreSQL” 高性能主从强一致读写分离,我行,你没戏!
全世界都在“搞” PostgreSQL ,从Oracle 得到一个“馊主意”开始
PostgreSQL 加索引系统OOM 怨我了--- 不怨你怨谁
PostgreSQL “我怎么就连个数据库都不会建?” --- 你还真不会!
PostgreSQL 稳定性平台 PG中文社区大会--杭州来去匆匆
PostgreSQL 分组查询可以不进行全表扫描吗?速度提高上千倍?
POSTGRESQL --Austindatabaes 历年文章整理
PostgreSQL 查询语句开发写不好是必然,不是PG的锅
这个 PostgreSQL 让我有资本找老板要 鸡腿 鸭腿 !!
MySQL相关文章
一篇为MySQL用户,分析版本核心差异的文章--8.028-8.4的差异
那个MySQL大事务比你稳定,主从延迟低,为什么? Look my eyes! 因为宋利兵宋老师