开头还是介绍一下群,如果感兴趣PolarDB ,MongoDB ,MySQL ,PostgreSQL ,Redis, OceanBase, Sql Server等有问题,有需求都可以加群群内有各大数据库行业大咖,可以解决你的问题。加群请联系 liuaustin3 ,(共2400人左右 1 + 2 + 3 + 4 +5 + 6 + 7)(1 2 3 4 5 群均已爆满,请不要在问有没有位置谢谢, 6群超过400人停止自由申请,7群开启)
MongoDB 最近一直在写文言文,但咱们MongoDB也是武行出身,今天就说说那些MongoDB的具有一些技术含量,且你需要的脚本,有这些脚本,能让小白快速解决一些问题,短暂冒充小专家。
这里需要注意,运行下面的脚本,一定要使用mongosh,不会装的看下面的,其实不用装,下载就放到Linux中的 /bin 中就可以了。
https://www.mongodb.com/try/download/shell
下面咱们就来顺序着来,8个JS脚本,咱们也不要版权,就是用的时候,想着点我好
脚本1:分析MongoDB 中所有库和每个库里面的collation的大小,存储空间整体索引使用的空间,等等,一个脚本可以让数据库里面所有的表大小你都获知。
这里注意,在链接得时候,你要有足够的权限,权限不够脚本运行不了,尤其是一些管理信息类的命令,你要是怕权限不够,可以直接用mongodb 的root权限账号来运行,这里注意 db = connect('mongodb://root:1234.Com@192.168.198.100:27027/admin') 每个脚本里面都有连接的信息,其中root是账号名,1234.Com 是密码,你可以将对应你的monogDB库的用户名密码替换即可,同时后面是IP和端口号 admin指的是admin库,下面是代码和每个代码运行后的结果图。
db = connect('mongodb://root:1234.Com@192.168.198.100:27027/admin');
var databases = db.adminCommand({ listDatabases: 1 }).databases;
databases.forEach(function(dbInfo) {
print("Database Name: " + dbInfo.name);
});
dbStats = db.runCommand({ dbStats: 1 });
collectionStats = db.getCollectionNames().map(function(collectionName) {
return db.getCollection(collectionName).stats();
});
print("=== Database Statistics ===");
print("Database Name: " + dbStats.db);
print("Number of Collections: " + collectionStats.length);
totalDocuments = 0;
totalAvgObjSize = 0;
totalDataSize = 0;
collectionStats.forEach(function(collection) {
totalDocuments += collection.count;
totalAvgObjSize += collection.avgObjSize || 0;
totalDataSize += collection.size;
print("Collection: " + collection.ns);
print(" Document Count: " + collection.count);
print(" Avg Object Size: " + (collection.avgObjSize / 1024).toFixed(2) + " KB");
print(" Collection Size: " + (collection.size / 1024 / 1024).toFixed(2) + " MB");
});
print("=== Summary ===");
print("Total Documents: " + totalDocuments);
print("Total Avg Object Size: " + (totalAvgObjSize / collectionStats.length / 1024).toFixed(2) + " KB");
print("Total Data Size: " + (totalDataSize / 1024 / 1024).toFixed(2) + " MB");
脚本2 第一个脚本没有汇总信息,第二个脚本有汇总信息,包含每个document的平均大小,和数据总体的尺寸。
db = connect('mongodb://root:1234.Com@192.168.198.100:27027/test');
var operations = db.currentOp();
var activeConnections = 0;
var idleConnections = 0;
var errorConnections = 0;
operations.inprog.forEach(function(op) {
if (op.hasOwnProperty('client')) {
print("Client Address: " + op.client);
print("App Name: " + (op.appName ? op.appName : "N/A"));
print("Operation ID (opid): " + op.opid);
print("Database: " + (op.ns ? op.ns.split('.')[0] : "N/A"));
print("Secs Running: " + (op.hasOwnProperty('secs_running') ? op.secs_running : "N/A") + " seconds");
if (op.active) {
activeConnections++;
print(" Status: Active");
} else if (!op.active && op.hasOwnProperty('secs_running') && op.secs_running == 0) {
idleConnections++;
print(" Status: Idle");
} else if (op.hasOwnProperty('msg') && op.msg == "error") {
errorConnections++;
print(" Status: Error");
}
print("");
}
});
print("\n=== Connection Summary ===");
print("Active Connections: " + activeConnections);
print("Idle Connections: " + idleConnections);
print("Error Connections: " + errorConnections);
脚本3 这个脚本是分析当前连接的,且总结当前链接中有多少活跃的链接,多少idle的,并打印出每个链接已经工作的时间
db = connect('mongodb://root:1234.Com@192.168.198.100:27027/test');
var operations = db.currentOp();
var activeConnections = 0;
var idleConnections = 0;
var errorConnections = 0;
operations.inprog.forEach(function(op) {
if (op.hasOwnProperty('client')) {
print("Client Address: " + op.client);
print("App Name: " + (op.appName ? op.appName : "N/A"));
print("Operation ID (opid): " + op.opid);
print("Database: " + (op.ns ? op.ns.split('.')[0] : "N/A"));
print("Secs Running: " + (op.hasOwnProperty('secs_running') ? op.secs_running : "N/A") + " seconds");
if (op.active) {
activeConnections++;
print(" Status: Active");
} else if (!op.active && op.hasOwnProperty('secs_running') && op.secs_running == 0) {
idleConnections++;
print(" Status: Idle");
} else if (op.hasOwnProperty('msg') && op.msg == "error") {
errorConnections++;
print(" Status: Error");
}
print("");
}
});
print("\n=== Connection Summary ===");
print("Active Connections: " + activeConnections);
print("Idle Connections: " + idleConnections);
print("Error Connections: " + errorConnections);
脚本4 这个脚本需要具有管理员权限,这个脚本是直接杀死在MongoDB 查询超过30秒的语句,当然时间你可以调
db = connect('mongodb://root:1234.Com@192.168.198.100:27027/test');
var operations = db.currentOp();
operations.inprog.forEach(function(op) {
if (op.secs_running > 30 && op.op === 'query' && !op.killPending) {
print("\n=== Query Details ===");
print("Operation ID (opid): " + op.opid);
print("Running for: " + op.secs_running + " seconds");
print("Client: " + op.client);
print("Database: " + (op.ns ? op.ns.split('.')[0] : "N/A"));
print("Collection: " + (op.ns ? op.ns.split('.')[1] : "N/A"));
print("Query: " + tojson(op.query));
var killOp = prompt("Kill this query? (Y/N): ");
if (killOp.toLowerCase() === 'y') {
print("Killing opid: " + op.opid);
db.killOp(op.opid);
} else {
print("Skipping opid: " + op.opid);
}
}
});
脚本 5 一般情况下,如果让你找当前的MongoDB中的query 是否有全表扫描,让你立即分析当前MongoDB运行的语句有没有全表扫描,怎么办,来脚本给你准备好了
db = connect('mongodb://root:1234.Com@192.168.198.100:27027/test');
var operations = db.currentOp();
function isTableScan(query) {
if (!query || Object.keys(query).length === 0) {
return true;
}
if (!query.hasOwnProperty('_id')) {
return true;
}
return false;
}
var hasTableScan = false;
operations.inprog.forEach(function(op) {
if (op.op === 'query' && !op.killPending) {
var query = op.query;
if (isTableScan(query)) {
hasTableScan = true;
print("\n=== Potential Table Scan Detected ===");
print("Operation ID (opid): " + op.opid);
print("Client: " + op.client);
print("Database: " + (op.ns ? op.ns.split('.')[0] : "N/A"));
print("Collection: " + (op.ns ? op.ns.split('.')[1] : "N/A"));
print("Query: " + tojson(query));
}
}
});
if (!hasTableScan) {
print("没有全表扫描。");
}
脚本 7 基本上MongoDB 大部分都是以replica的形式来出现的,那么怎么分析你的复制有没有延迟,你的这几个节点都是谁,都是什么关系,那就得用下面两个脚本
第一个分析节点之间的关系,且这些库是否正常
db = connect('mongodb://root:1234.Com@192.168.198.100:27027/test');
var serverStatus = db.serverStatus();
print("MongoDB 启动时间 (秒): " + serverStatus.uptime);
var isMaster = db.isMaster();
if (isMaster.ismaster) {
print("MongoDB 运行模式: 主库 (Primary)");
} else if (isMaster.secondary) {
print("MongoDB 运行模式: 从库 (Secondary)");
} else {
print("MongoDB 运行模式: 单机或其他");
}
if (isMaster.setName) {
print("副本集名称: " + isMaster.setName);
var replStatus = rs.status();
replStatus.members.forEach(function(member) {
print("\n成员: " + member.name);
print(" 状态: " + member.stateStr);
if (member.stateStr === "PRIMARY") {
print(" 角色: 主库 (Primary)");
} else if (member.stateStr === "SECONDARY") {
print(" 角色: 从库 (Secondary)");
} else if (member.stateStr === "ARBITER") {
print(" 角色: 仲裁节点 (Arbiter)");
} else if (member.hidden) {
print(" 角色: 隐藏节点 (Hidden)");
}
print(" 健康状态: " + (member.health === 1 ? "正常" : "异常"));
if (member.syncingTo) {
print(" 正在同步: " + member.syncingTo);
}
if (member.electionDate) {
print(" 最近的主节点选举时间: " + member.electionDate);
}
});
} else {
print("MongoDB 不是副本集,可能是单机模式。");
}
第二个脚本,是分析复制结合中是否有延迟
db = connect('mongodb://root:1234.Com@192.168.198.100:27027/test');
var replStatus = rs.status();
var primaryOptime = null;
replStatus.members.forEach(function(member) {
if (member.stateStr === "PRIMARY") {
primaryOptime = member.optimeDate; // 主节点的 optimeDate
print("主节点: " + member.name);
print("主节点最后操作时间 (optime): " + primaryOptime);
}
});
replStatus.members.forEach(function(member) {
if (member.stateStr === "SECONDARY") {
print("\n从节点: " + member.name);
var secondaryOptime = member.optimeDate;
print("从节点最后操作时间 (optime): " + secondaryOptime);
var lagSeconds = (primaryOptime - secondaryOptime) / 1000; // 将毫秒转换为秒
if (lagSeconds > 0) {
print("延迟时间 (秒): " + lagSeconds);
} else {
print("无延迟");
}
if (member.syncingTo) {
print("正在从节点同步: " + member.syncingTo);
}
}
});
脚本 8 MongoDB的慢查询和其他的数据库不太一样,因为速度太快,太多的慢查询信息会对数据库的性能产生影响,所以一般MongoDB DBA的习惯是需要的时候打开慢查询,不需要的时候关上,所以这个脚本就是一个这样的脚本,默认打开,然后收集10分钟的慢查询后,将信息打印出来,这里如果要记录可以用LINUX 的 > 重定向将打印的信息重定向到文件中,后面在分析。
db = connect('mongodb://root:1234.Com@192.168.198.100:27027/test');
print("正在设置慢查询阈值为 100 毫秒...");
db.setProfilingLevel(1, 100);
function collectSlowQueries() {
print("\n=== 收集到的慢查询日志 ===");
var slowQueries = db.system.profile.find({
millis: { $gt: 100 }
}).sort({ ts: -1 });
slowQueries.forEach(function(query) {
print("查询时间: " + query.ts);
print("执行时间 (毫秒): " + query.millis);
if (query.query) {
print("查询操作: ");
printjson(query.query);
} else {
print("查询操作: 无查询条件 (如 insert 操作)");
}
print("数据库: " + query.ns);
if (query.op) {
print("完整操作: " + query.op);
} else {
print("完整操作: 无详细操作类型");
}
print("\n");
});
}
print("开始记录慢查询日志,等待 10 分钟...");
var startTime = new Date().getTime();
var elapsed = 0;
var waitTime = 10 * 60 * 1000;
while (elapsed < waitTime) {
var currentTime = new Date().getTime();
elapsed = currentTime - startTime;
}
print("收集 10 分钟内的慢查询...");
collectSlowQueries();
db.setProfilingLevel(0);
print("已关闭慢查询日志记录。");
以上就是今天给大家分享的8个MongoDB的管理脚本,有的还可以进行改造,但请注意里面有一个问题,部分脚本的默认库是test,那么你的数据库里面就没有test 那么就一定会报错,所以,如果你连这个都不懂,还是先弄懂MongoDB的连接串和简单的与原理在用,我怕你部分脚本乱搞,惹祸。
置顶文章:
撕逼!PostgreSQL 和 MongoDB 开撕,MySQL却躺枪
MongoDB 系统IOPS 告警系统处于崩溃,优化语句从1秒优化到1毫秒解决问题
MongoDB 入门教学贴 从术语到操作 (约束怎么建立 内部培训贴)
MongoDB 谨献给说MongoDB 这不好那不好的“古董” -- 发展与演进,从3 到 7 的卓越变化
专访唐建法-从MongoDB中国第一人到TapData掌门人的故事
往期热门文章:
微软 “爱” 上PostgreSQL, PG “嫁给” 微软!
PostgreSQL 软肋 “最大连接数” 到底是不是问题?
阿里云数据库--市场营销聊胜于无--3年的使用感受与反馈系列
阿里云数据库产品 对内对外一样的卷 --3年阿里云数据库的使用感受与反馈系列
阿里云数据库使用感受--客户服务问题深入剖析与什么是廉价客户 --3年的使用感受与反馈系列
阿里云数据库使用感受--操作界面有点眼花缭乱 --3年的使用感受与反馈系列
PolarDB 最近遇到加字段加不上的问题 与 使用PolarDB 三年感受与恳谈
PostgreSQL 稳定性平台 PG中文社区大会--杭州来去匆匆
MySQL 的SQL引擎很差吗?由一个同学提出问题引出的实验
临时工访谈:从国产数据库 到 普罗大众的产品 !与在美国创业软件公司老板对话
感谢 老虎刘 刘老师 对 5月20日 SQL 问题纠正贴 ---PostgreSQL 同一种SQL为什么这样写会提升45%性能
PostgreSQL 同一种SQL为什么这样写会提升45%性能 --程序员和DBA思维方式不同决定
PostgreSQL 熊灿灿一句话够学半个月 之 KILL -9
临时工访谈:庙小妖风大-PolarDB 组团镇妖 之 他们是第一 (阿里云组团PK笔者实录)
临时工访谈:金牌 “女” 销售从ORACLE 转到另类国产数据库 到底 为什么?
临时工访谈:无名氏意外到访-- 也祝你好运(管理者PUA DBA现场直播)