MongoDB 慢查询优化

news/2025/2/12 18:36:23/文章来源:https://www.cnblogs.com/jhfnewstart/p/18711999

MongoDB 慢查询深度优化指南(检测→分析→调优)


一、慢查询检测体系

1. 三层检测机制

graph TDA[实时检测] --> B[Profiling日志]C[持续监控] --> D[Database Profiler]E[深度分析] --> F[Explain+执行计划]

2. 生产级Profile配置

// Java驱动开启Profiling
MongoDatabase adminDb = mongoClient.getDatabase("admin");
Document profileCommand = new Document().append("setProfilingLevel", 1).append("slowms", 100)  // 100ms阈值.append("sampleRate", 0.5); // 采样率
adminDb.runCommand(profileCommand);

3. 监控指标关联

# 慢查询关键指标(Prometheus)
mongodb_ss_opLatencies_reads_latency{instance="mongo1:9100"} > 100
mongodb_ss_opLatencies_writes_latency{instance="mongo1:9100"} > 200
mongodb_ss_cursor_open_total{state="timedOut"} > 0

二、执行计划深度解析

1. Explain结果关键字段

{"queryPlanner": {"winningPlan": {"stage": "COLLSCAN", // 全表扫描"filter": {"$match": {...}},"direction": "forward"},"rejectedPlans": [...] },"executionStats": {"executionTimeMillis": 128,"totalKeysExamined": 0,  // 未使用索引"totalDocsExamined": 1000000,"executionStages": {"stage": "COLLSCAN","nReturned": 10,"works": 1000002}}
}

2. 性能问题模式识别

// 识别低效查询模式
public class QueryAnalyzer {public void analyzeExplainResult(Document explainResult) {if ("COLLSCAN".equals(explainResult.get("stage"))) {if (explainResult.getInteger("totalDocsExamined") > 10000) {logger.warn("全表扫描告警: {}", explainResult);}}if (explainResult.getDouble("executionTimeMillis") > 100) {logger.error("慢查询告警: {}ms", explainResult.getDouble("executionTimeMillis"));}}
}

3. 索引覆盖检查

// 验证覆盖查询
public boolean isCoveredQuery(Document explainResult) {return explainResult.getInteger("totalDocsExamined") == 0 && explainResult.getInteger("totalKeysExamined") > 0;
}// 创建覆盖索引示例
collection.createIndex(Indexes.compoundIndex(Indexes.ascending("status", "create_time"),Indexes.include("order_no")
));

三、索引优化实战

1. 索引选择矩阵

查询模式 推荐索引类型 示例
等值查询+范围排序 复合索引(等值在前) {status:1, create_time:-1}
多字段排序 复合索引匹配排序顺序 {category:1, price:-1}
正则表达式搜索 前缀索引+Collation {title:1}, collation{locale:'en', strength:2}
全文检索 文本索引 {description:"text"}

2. 索引性能验证

// 索引效率对比测试框架
public class IndexBenchmark {public void runBenchmark(String indexField, Query query) {collection.dropIndex(indexField);// 无索引测试long timeWithout = measureQueryTime(query);collection.createIndex(Indexes.ascending(indexField));// 有索引测试long timeWith = measureQueryTime(query);logger.info("索引[{}]性能提升: {}ms → {}ms ({}%)", indexField, timeWithout, timeWith, (timeWithout - timeWith)*100/timeWithout);}
}

3. 索引维护策略

# 索引重建维护脚本
mongo --eval "db.getCollection('orders').reIndex()" # 后台索引构建
db.orders.createIndex({product_id:1}, {background: true})

四、查询优化技巧

1. 分页优化方案对比

// 传统分页(性能差)
FindIterable<Document> results = collection.find(query).skip((pageNum - 1) * pageSize).limit(pageSize);// 游标分页(推荐)
Bson lastId = ...; // 上一页最后记录的_id
FindIterable<Document> results = collection.find(and(query, gt("_id", lastId))).limit(pageSize).sort(Sorts.ascending("_id"));

2. 聚合管道优化

// 低效管道
Aggregates.match(where("status").is("active")),
Aggregates.unwind("$items"),
Aggregates.group("$items.category")// 优化后(提前过滤)
Aggregates.match(and(where("status").is("active"),where("items").exists(true)
)),
Aggregates.project(fields(include("items"),computed("filteredItems", filter("$items", "item", where("item.stock").gt(0))
)),
Aggregates.unwind("$filteredItems")

3. 内存控制技巧

// 允许磁盘缓存(避免内存溢出)
AggregationOptions options = AggregationOptions.builder().allowDiskUse(true).build();collection.aggregate(pipeline, options);

五、系统级调优

1. 内存配置黄金法则

# mongod.conf 生产配置
storage:wiredTiger:engineConfig:cacheSizeGB: 24  # 总内存的50-60%collectionConfig:blockCompressor: snappyindexConfig:prefixCompression: truesystemLog:logAppend: truepath: /var/log/mongodb/mongod.logoperationProfiling:mode: slowOpslowOpThresholdMs: 100

2. 锁竞争优化

# 查看当前锁状态
db.currentOp(true).inprog.forEach(function(op) { if (op.locks) printjson(op.locks)}
)# 优化方案:
# 1. 使用$atomic替代大范围更新
# 2. 分片集群分散压力
# 3. 升级到MongoDB 4.0+使用乐观并发控制

六、典型案例分析

案例1:电商订单查询慢

  • 问题现象

    • 按用户ID+时间范围查询订单耗时>1s
    • 存在大量COLLSCAN
  • 优化步骤

    1. 创建复合索引:
    collection.createIndex(Indexes.compoundIndex(Indexes.ascending("user_id"), Indexes.descending("create_time")
    ));
    
    1. 改写查询:
    Bson query = and(eq("user_id", userId),gte("create_time", startDate),lte("create_time", endDate)
    );
    
    1. 执行计划验证:
    "winningPlan": {"stage": "IXSCAN","indexName": "user_id_1_create_time_-1"
    }
    

案例2:物联网设备数据聚合慢

  • 问题现象

    • 每日设备状态统计耗时5分钟+
    • 内存溢出导致频繁磁盘交换
  • 优化方案

    1. 启用时间分桶模式:
    @Document
    public class DeviceStatus {private String deviceId;private int hourBucket; // 小时级分桶private List<MinuteData> minutes; 
    }
    
    1. 优化聚合管道:
    List<Bson> pipeline = Arrays.asList(match(and(eq("deviceId", deviceId), gte("hourBucket", startHour),lte("hourBucket", endHour))),unwind("$minutes"),group(null, avg("avgTemp").avg("$minutes.temperature"),max("maxVoltage").max("$minutes.voltage"))
    );
    
    1. 配置allowDiskUse并添加索引:
    collection.createIndex(Indexes.compoundIndex(Indexes.ascending("deviceId"),Indexes.ascending("hourBucket")
    ));
    

七、自动化优化工具链

1. 慢查询分析工具

# 使用mtools进行日志分析
mloginfo --queries mongod.log
mlogfilter mongod.log --slow --json | mplotqueries# 输出可视化图表:
# - 查询类型分布
# - 执行时间热力图
# - 扫描/返回文档比例

2. 索引建议工具

// 使用index advisor
db.collection.aggregate([{$indexStats: {}},{$match: {accesses: {$gt: 1000}}},{$sort: {"accesses.ops": -1}}
])

3. 自动化索引管理

// 基于查询模式的自动索引推荐
public class AutoIndexer {public void analyzeQueries() {List<Document> slowQueries = profileCollection.find(gt("millis", 100)).into(new ArrayList<>());slowQueries.forEach(query -> {QueryAnalyzer analyzer = new QueryAnalyzer(query);analyzer.recommendIndex();});}
}

八、预防性优化策略

1. 开发规范

1. **查询规范**:- 禁止不带条件的`find({})`- `$in`数组大小不超过1000- 更新操作必须带条件2. **索引规范**:- 组合索引不超过4个字段- 单集合索引数不超过10个- 索引内存占用不超过工作集大小3. **设计规范**:- 文档大小不超过16MB- 嵌套层级不超过5层- 时间序列数据必须分桶

2. 压力测试方案

// 使用JMeter进行负载测试
public class MongoStressTest {@Testvoid testQueryPerformance() {MongoTemplate template = ...;IntStream.range(0, 10000).parallel().forEach(i -> {Query query = Query.query(where("status").is("active").and("createTime").gte(LocalDateTime.now().minusDays(7))).with(Sort.by(Sort.Direction.DESC, "priority"));template.find(query, Order.class); // 记录响应时间});}
}

3. 容量规划模型

// 数据增长预测算法
public class CapacityPlanner {public StorageInfo forecastGrowth(String collectionName) {Document stats = db.runCommand(new Document("collStats", collectionName));double dailyGrowth = stats.getDouble("avgObjSize") * getInsertOpsPerDay(collectionName);return new StorageInfo(LocalDate.now().plusDays(30),stats.getDouble("size") + dailyGrowth * 30);}
}

九、深度调优清单

优化方向 检查项 达标标准
索引 所有查询都使用索引 explain显示IXSCAN
内存 工作集完全放入内存 wiredTiger缓存命中率>95%
查询 无超过100ms的慢查询 Profiling日志无告警
连接 连接池利用率<80% maxPoolSize配置合理
存储 磁盘IO延迟<10ms iostat显示无持续高负载
安全 开启角色访问控制 无匿名访问权限

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/882681.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

商家智能助手:多智能体在电商垂域的技术探索

引言 多智能体的架构演进过程: 第一阶段:B商城工单自动回复,LLM和RAG结合知识库应答,无法解决工具调用。 第二阶段:京东招商站,单一Agent处理知识库问答和工具调用,准确率低 & LLM模型幻觉,场景区分度差。 第三阶段:京麦智能助手,引入multi-agent架构,master + …

Agent应用实战:从广告智能助手落地到平台化赋能

前言 自2022年底ChatGPT发布以来,大模型成为非常火爆的话题。如何在生活和工作中把大模型用的更好、更具价值,业界一致认为Agent是其中一个重要的方向。下面就分享一下我们京东广告在Agent应用上的一些实践和经验,希望能给大家带来一定的启发和思考。一、Agent 在京东广告投…

换根 DP:进阶练习笔记

前言观前提醒:本文非新手向文章,不建议作为换根 DP 入门使用。 本文在洛谷专栏、博客园、CSDN同步发送。换根 DP 是树状 DP 的一种,思维难度较高,但是学会以后很套路也很轻松。 例题 P3047 [USACO12FEB] Nearby Cows G对于每个节点求出距离它不超过 \(k\) 的所有节点权值和…

clion 执行CMake 报错:Cannot read xxx\CMakeFiles\TargetDirectories.txt

在Windows下使用Mingw32编译,Clion 执行CMake时报错:D:\Develop\CLion-2021.1.3.win\bin\cmake\win\bin\cmake.exe -DCMAKE_BUILD_TYPE=Debug -G "CodeBlocks - MinGW Makefiles" D:\Work\C++Work\HelloWorld -- The C compiler identification is GNU 8.1.0 -- Th…

XXE

XXE漏洞产生原因 XXE漏洞:XML外部实体注入漏洞;应用程序解析XML输入时,没有对上传的XML文件内容进行过滤,没有禁止外部实体的加载,导致可以加载恶意外部文件,造成文件读取、命令执行、内网端口扫描、DOS攻击等。 XXE与HTML XML是可扩展标记语言、重点在传输数据和存储数据…

官媒报纸下载器 | 快速下载电子版报纸

报纸下载器是一款可以快速下载电子版报纸的应用,无需安装双击即可使用。 它支持人民日报、农民日报、经济日报、中国证券报、工人日报、科技日报等多家官方报纸的在线下载。 可选择报纸并设置日期,点击下载按钮后,报纸将以PDF格式下载到本地。 下载进度和版面信息会在底部状…

反序列化

序列化与反序列化 序列化:把一个对象类型的数据转换成字符串(字节流)进行传输,把某个对象系列化成JSON格式或XML格式或者其他序列化格式的字符串过程称为序列化。 反序列化:将字节流或字符串转换为原始的数据结构或对象。 shiro反序列化 shiro-550:shiro < 1.2.5 主要是…

RockyLinux操作系统

RockyLinux操作系统 1 系统介绍 2020 年 12 月 8 日,Red Hat 宣布他们将停止开发 CentOS,CentOS 一直是 Red Hat Enterprise Linux 的生产就绪下游版本,转而支持该作系统的较新的上游开发变体,称为“CentOS Stream”。作为回应,CentOS 的最初创办人 Gregory Kurtzer 在 Ce…

域名解析—互联网世界的导航系统

在互联网的世界里,每个网站都像一座“城市”,而用户要找到这些“城市”,必须依赖一套精准的导航系统——这就是域名解析。无论是浏览网页、发送邮件,还是使用移动应用,域名解析都在背后默默支撑着用户的每一次访问。本文将深入浅出地解析域名解析的原理、流程及其在互联网…

算法备案办理经验分享

算法备案实际办理经验,包含流程、材料和注意事项作为一名算法备案代办服务人员,之前又有一批客户通过了算法备案。趁着最近闲下来,今天就跟大伙分享下我做算法备案的经验,如有任何疑问,欢迎大家直接提问。一、算法备案流程 1.注册与主体信息提交 首先得登录互联网信息服务…

基于Ollama+DeepSeek+AnythingLLM轻松投喂打造本地大模型知识库.250212

第一步,下载开源的[AI]应用程序AnythingLLM 去官网Download AnythingLLM for Desktop下载并安装即可。 第二步,下载Ollama并获取DeepSeek LLM) 为了使用DeepSeek我们需要先下载Ollama并获取DeepSeek。 1、打开 Ollama 的官网http://ollama.com,在官网找到 “Download”,点击…