Java-151 深入浅出 MongoDB 索引详解 性能优化:慢查询分析 索引调优 快速定位并解决慢查询

点一下关注吧!!!非常感谢!!持续更新!!!

🚀 AI篇持续更新中!(长期更新)

AI炼丹日志-31- 千呼万唤始出来 GPT-5 发布!"快的模型 + 深度思考模型 + 实时路由",持续打造实用AI工具指南!📐🤖

💻 Java篇正式开启!(300篇)

目前2025年10月13日更新到:
Java-147 深入浅出 MongoDB 分页查询详解:skip() + limit() + sort() 实现高效分页、性能优化与 WriteConcern 写入机制全解析

MyBatis 已完结,Spring 已完结,Nginx已完结,Tomcat已完结,分布式服务正在更新!深入浅出助你打牢基础!

📊 大数据板块已完成多项干货更新(300篇):

包括 Hadoop、Hive、Kafka、Flink、ClickHouse、Elasticsearch 等二十余项核心组件,覆盖离线+实时数仓全栈!
大数据-278 Spark MLib - 基础介绍 机器学习算法 梯度提升树 GBDT案例 详解

慢查询分析

内置分析器

MongoDB提供了内置的查询分析器(profiler),用于监控和记录数据库的读写操作性能。通过db.setProfilingLevel(n,m)命令可以开启分析器功能,该功能会记录所有CRUD操作以及命令执行的详细信息,包括执行时间、索引使用情况等。

分析器级别设置

  1. 级别0(关闭分析)

    • 用法:db.setProfilingLevel(0)
    • 这是默认设置,不会记录任何操作信息
    • 适用于生产环境中不需要监控查询性能的场景
  2. 级别1(记录慢查询)

    • 用法:db.setProfilingLevel(1, m)
    • 其中m单位为毫秒(ms),表示慢查询阈值
    • 例如:db.setProfilingLevel(1, 100)会记录执行时间超过100ms的操作
    • 记录的信息会存储在system.profile集合中
    • 典型应用场景:生产环境性能调优
  3. 级别2(记录所有操作)

    • 用法:db.setProfilingLevel(2)
    • 会记录所有读写操作,无论执行时间长短
    • 会产生大量日志数据,影响性能
    • 主要用于开发和测试环境进行全面分析

使用示例

javascript 复制代码
// 设置记录慢于50ms的查询
db.setProfilingLevel(1, 50)

// 查看当前分析级别
db.getProfilingLevel()

// 查看分析状态详细信息
db.getProfilingStatus()

// 查询记录的分析数据
db.system.profile.find().sort({ts:-1}).limit(10)

注意事项

  • 分析记录存储在system.profile集合中,这是一个固定大小的集合
  • 默认大小为1MB,可以通过db.createCollection()修改
  • 高级别分析会产生大量数据,可能影响性能
  • 建议在生产环境中使用级别1,并设置合理的阈值
  • 分析数据包含丰富信息:执行时间、扫描文档数、索引使用情况等

查询监控结果

这个命令用于查询 MongoDB 数据库的性能分析数据,它会返回执行时间最长的 3 个操作记录。具体分析如下:

  1. db.system.profile

    • 这是 MongoDB 内置的性能分析集合
    • 需要先通过 db.setProfilingLevel(1) 启用性能分析功能才会记录数据
    • 默认情况下 profile 集合大小为 1MB
  2. find()

    • 查询 profile 集合中的所有文档
    • 可以添加查询条件,如 find({op: "query"}) 只查询查询操作
  3. sort({ millis: -1 })

    • 按执行时间(milliseconds)降序排序
    • -1 表示降序,1 表示升序
    • millis 字段记录了操作执行耗时
  4. limit(3)

    • 限制返回的记录数为3条
    • 通过这个参数可以控制返回的慢查询数量

应用场景:

  • 数据库性能调优时,识别耗时最长的操作
  • 排查特定时间段内的性能问题
  • 监控常规业务操作的执行效率

输出结果包含的重要字段:

  • ts:操作时间戳
  • op:操作类型(query/insert/update/delete)
  • ns:操作的命名空间(数据库.集合)
  • millis:操作耗时(毫秒)
  • query:执行的查询条件
  • planSummary:查询执行计划

我这里没有慢查询···

数据库性能问题分析

1. 应用程序设计不合理

  • 问题表现:应用程序中存在频繁的短连接、未优化的 SQL 查询、大量小事务或 N+1 查询问题。
  • 影响:导致数据库连接池耗尽、查询效率低下、事务竞争激烈。
  • 示例
    • 频繁创建和关闭数据库连接,而非使用连接池。
    • 未使用批量操作,而是循环执行单条 SQL(如 for 循环插入 1000 条数据)。
    • 未合理使用缓存,导致重复查询相同数据。

2. 不正确的数据类型

  • 问题表现 :字段类型与实际数据不匹配,如使用 VARCHAR(255) 存储数字,或 TEXT 存储短字符串。
  • 影响
    • 存储空间浪费(如 INTVARCHAR 更高效)。
    • 查询性能下降(如字符串比较比数字比较慢)。
    • 索引效率降低(如 LIKE 模糊查询无法有效利用索引)。
  • 示例
    • 使用 DATETIME 存储时间戳,而非更轻量的 TIMESTAMP(如果时间范围允许)。
    • 使用 VARCHAR 存储枚举值,而非 ENUMTINYINT

3. 硬件配置问题

  • 问题表现:数据库服务器 CPU、内存、磁盘 I/O 或网络带宽不足。
  • 影响
    • 查询响应慢,甚至超时。
    • 高并发时系统崩溃或频繁卡死。
  • 常见场景
    • 内存不足 :未合理分配缓冲池(如 InnoDB 的 innodb_buffer_pool_size),导致频繁磁盘读写。
    • 磁盘 I/O 瓶颈:使用机械硬盘而非 SSD,或 RAID 配置不合理。
    • CPU 过载:复杂查询、全表扫描或未优化的存储过程占用大量 CPU。

4. 缺少索引

  • 问题表现:频繁执行全表扫描,而非索引扫描。
  • 影响:查询速度随数据量增长急剧下降。
  • 常见问题
    • 未对 WHEREJOINORDER BYGROUP BY 字段建立索引。
    • 索引设计不合理(如单列索引过多,但未使用复合索引)。
    • 索引失效(如对索引列使用函数或计算,如 WHERE YEAR(date_column) = 2023)。
  • 优化建议
    • 使用 EXPLAIN 分析查询执行计划,识别缺失的索引。
    • 避免过度索引(索引会增加写入开销)。

5. 其他常见问题

  • 锁竞争:长事务、未提交的事务或行锁升级为表锁,导致并发性能下降。
  • 大表未分库分表:单表数据量过大(如千万级),导致查询和维护困难。
  • 未定期维护 :如未执行 OPTIMIZE TABLEANALYZE TABLE,导致统计信息不准确。

通过系统化的分析和优化,可以有效提升数据库性能,避免潜在瓶颈。

EXPLAIN 基础概念

EXPLAIN 是 MySQL 提供的用于分析 SQL 查询执行计划的工具,它能够展示 MySQL 如何执行 SELECT 语句,包括如何使用索引、表连接顺序等重要信息。

EXPLAIN 输出字段详解

1. id 列

  • 表示查询中 SELECT 操作的顺序号
  • id 越大执行优先级越高
  • id 相同则从上往下执行
  • id 为 NULL 表示是结果集(如 UNION 结果)

2. select_type 列

  • SIMPLE:简单查询(不包含子查询或 UNION)
  • PRIMARY:主查询(包含子查询时最外层查询)
  • SUBQUERY:子查询(SELECT 或 WHERE 中的子查询)
  • DERIVED:派生表(FROM 子句中的子查询)
  • UNION:UNION 中的第二个或后续查询
  • UNION RESULT:UNION 的结果

3. table 列

  • 显示查询涉及的表名
  • 可能是表名、派生表名(如 derivedN)或 UNION 结果(如 union1,2)

4. partitions 列

  • 显示查询将访问的分区
  • 未分区表显示 NULL

5. type 列(重要)

表示表的访问方式,从最好到最差排序:

  • system:表只有一行记录(系统表)
  • const:通过主键或唯一索引等值查询
  • eq_ref:多表连接时使用主键或唯一索引关联
  • ref:使用非唯一索引等值查询
  • fulltext:全文索引检索
  • ref_or_null:类似 ref,但包含 NULL 值查询
  • index_merge:索引合并优化
  • unique_subquery:IN 子查询使用主键
  • index_subquery:IN 子查询使用非唯一索引
  • range:索引范围扫描
  • index:全索引扫描(索引覆盖)
  • ALL:全表扫描(最差情况)

6. possible_keys 列

  • 显示可能使用的索引
  • 如果为 NULL,表示没有可能的索引

7. key 列

  • 实际使用的索引
  • 如果为 NULL,表示没有使用索引

8. key_len 列

  • 索引使用的字节数
  • 可判断索引是否完全使用(复合索引的使用情况)

9. ref 列

  • 显示索引的哪一列被使用
  • 可能是 const、func 或列名

10. rows 列

  • MySQL 预估需要检查的行数
  • 重要优化指标(越小越好)

11. filtered 列

  • 表示存储引擎返回的数据在 server 层过滤后剩余的比例
  • 100% 表示没有过滤

12. Extra 列(重要)

包含额外信息:

  • Using index:使用覆盖索引
  • Using where:在存储引擎检索后再过滤
  • Using temporary:使用临时表
  • Using filesort:需要额外排序
  • Range checked for each record:没有好索引可用
  • Impossible WHERE:WHERE 条件永远为 false

常见优化场景分析

1. 全表扫描(type=ALL)

问题 :没有使用索引
解决方案

  • 为 WHERE 条件列添加合适索引
  • 检查索引是否失效(如函数操作导致索引失效)

2. 文件排序(Using filesort)

问题 :ORDER BY 没有使用索引
解决方案

  • 为 ORDER BY 列添加索引
  • 创建包含 WHERE 和 ORDER BY 列的复合索引

3. 临时表(Using temporary)

问题 :GROUP BY 或 DISTINCT 操作需要临时表
解决方案

  • 优化 GROUP BY 查询
  • 添加合适的索引

4. 索引覆盖(Using index)

良好情况:查询只需要通过索引就能获取所需数据

高级分析技巧

1. 分析复合索引使用

通过 key_len 可以判断复合索引的使用情况:

  • 计算每个字段类型占用的字节数
  • 比较 key_len 与完整索引长度判断是否部分使用

2. 执行计划可视化

  • 使用 MySQL Workbench 可视化执行计划
  • 使用 pt-visual-explain 工具生成可视化图表

3. 对比 EXPLAIN 和实际执行

  • 使用 EXPLAIN ANALYZE(MySQL 8.0+)获取实际执行统计
  • 使用 performance_schema 监控实际查询执行

实战优化案例

案例1:慢查询优化

sql 复制代码
EXPLAIN SELECT * FROM orders WHERE customer_id = 100 AND status = 'shipped' ORDER BY order_date DESC;

分析

  • 可能缺少 (customer_id, status, order_date) 的复合索引
  • 检查 type 是否为 ref 或 range
  • 检查 Extra 是否有 Using filesort

案例2:分页查询优化

sql 复制代码
EXPLAIN SELECT * FROM products LIMIT 10000, 20;

分析

  • 大偏移量分页性能差
  • 可优化为基于索引的分页查询

EXPLAIN 格式扩展

MySQL 8.0 支持多种 EXPLAIN 格式:

  • EXPLAIN FORMAT=TRADITIONAL:传统表格格式
  • EXPLAIN FORMAT=JSON:JSON 格式(包含更多细节)
  • EXPLAIN FORMAT=TREE:树形格式(8.0.16+)

注意事项

  1. EXPLAIN 不会实际执行查询,只是预测执行计划
  2. 统计信息可能不准确,导致执行计划与实际不符
  3. 在优化前后都应使用 EXPLAIN 验证效果
  4. 复杂查询可能需要结合多种优化手段
相关推荐
Han.miracle19 小时前
数据结构——二叉树的从前序与中序遍历序列构造二叉树
java·数据结构·学习·算法·leetcode
北冥湖畔的燕雀19 小时前
C++泛型编程(函数模板以及类模板)
开发语言·c++
Le1Yu20 小时前
分布式事务以及Seata(XA、AT模式)
java
寒山李白20 小时前
关于Java项目构建/配置工具方式(Gradle-Groovy、Gradle-Kotlin、Maven)的区别于选择
java·kotlin·gradle·maven
QX_hao21 小时前
【Go】--map和struct数据类型
开发语言·后端·golang
你好,我叫C小白21 小时前
C语言 循环结构(1)
c语言·开发语言·算法·while·do...while
无妄无望21 小时前
docker学习(4)容器的生命周期与资源控制
java·学习·docker
MC丶科21 小时前
【SpringBoot 快速上手实战系列】5 分钟用 Spring Boot 搭建一个用户管理系统(含前后端分离)!新手也能一次跑通!
java·vue.js·spring boot·后端
千码君20161 天前
React Native:从react的解构看编程众多语言中的解构
java·javascript·python·react native·react.js·解包·解构
夜白宋1 天前
【word多文档docx合并】
java·word