❝开头还是介绍一下群,如果感兴趣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群 200+,开10群PolarDB专业学习群100+)
MySQL SQL 优化指南 SQL 四句真言(优化系列 3)
SQL SERVER SQL 优化指南 四句真言 (SQL 优化系列 2)
PostgreSQL SQL 优化指南 四句真言(SQL 优化系列 1)
这是SQL优化的第四期了,这回终于转到了MongoDB。或者这个题目不对,MongoDB没有SQL,有的是自己的查询语句体系NoSQL。但大差不差,其实和传统数据库也有类似的地方。今天就说说MongoDB的SQL优化的四句真言。
文档设计很重要,NOSQL优化放后面,
索引类型比较多,遵守ESR的原则,
数据写入与更新,可以同步也异步,
聚合操作要注意,提前过滤再聚合。
MongoDB的数据库查询优化,与传统的数据库有很大的不同,举一个例子,传统数据库是先把饭做出来,在调味,而mongodb的优化应该是先把味道调整好了,在做饭。
所以这就导致一个大的问题,一般DBA没法管好MongoDB,或者没有那个思维的模式来管理,还是按照传统数据库的方式去优化,我们来挨个句子解释。
第一句是模式很重要,这里的模式就是告诉你,建集合(表)的时候非常重要,因为他是无结构化的模式,如果没有设计的规则,查询语句的撰写就更天马行空了,所以模式的选择很重要。
那么ESR原则是什么,这个MySQL的DBA肯能知道后,会温故而知新,与MySQL建立索引的原则有异曲同工之妙。ESR是什么。
👉 E (Equality) — 等值
👉 S (Sort) — 排序
👉 R (Range) — 范围
我们举一个例子,来说明这个原则
db.orders.insertMany([
{ order_id: 1, user_id: 101, status: "PAID", order_date: ISODate("2025-08-01"), total: 500 },
{ order_id: 2, user_id: 102, status: "PENDING", order_date: ISODate("2025-08-02"), total: 200 },
{ order_id: 3, user_id: 101, status: "PAID", order_date: ISODate("2025-08-05"), total: 1000 },
{ order_id: 4, user_id: 103, status: "CANCELLED", order_date: ISODate("2025-08-08"), total: 50 }
]);
db.orders.find(
{ user_id: 101, status: "PAID", total: { $gte: 500 } }
).sort({ order_date: -1 });
db.orders.createIndex(
{ user_id: 1, status: 1, order_date: -1, total: 1 }
);
一句话解释,建立索引的字段顺序是,先等值,然后把需要排序的字段放入,最后才是范围的查询字段。按照这个顺序建立的联合索引才是最优的。
第二句,索引类型较多的问题,这里简单列一下MongoDB的索引类型单键索引、复合索引、稀疏索引、部分索引、TTL 索引、全文索引、地理空间索引、哈希索引等等。
这里解释一下传统数据库中没有的索引类型
1 部分索引,部分索引可不是传统DBA理解的 ,一个字段取其中的字段值的模糊索引,NO NO NO。这个部分索引是,查询字段查那个给那个字段的值建立索引。传统DBA 估计把脑袋撞破也不理解。 举个例子吧: 我们有一个
{
_id: ObjectId(),
order_id: Number,
user_id: Number,
amount: Number,
status: String, 可能的取值:CREATED, PAID, CANCELLED, REFUNDED
created_at: Date
}
这里我们查询中的条件只有PAID
db.orders.find({ status: "PAID" })
那么我们的部分索引就建立成
db.orders.createIndex(
{ status: 1 },
{ partialFilterExpression: { status: "PAID" } }
)
db.orders.find({ status: "PAID" }).explain("executionStats")
"winningPlan": {
"stage": "IXSCAN",
"indexName": "status_1_partial"
}
这在传统数据库是无法实现,不能想象的,那为什么MongoDB可以这样做,原因就在于节省有效的索引空间,只记录 PAID的字段的物理位置,不查询的那些字段都不记录,最大化的通过自由的手段来优化查询,速度一定是非常快,但前提是你的理解业务。
第二个是传统DBA不曾见过的稀疏索引,稀疏索引(Sparse Index)只为存在某字段的文档建立索引。没有该字段的文档不会进入索引
我们还是举一个例子
db.orders.insertMany([
{ order_id: 1, user_id: 101, amount: 500, status: "PAID" },
{ order_id: 2, user_id: 102, amount: 200 }, 无 status
{ order_id: 3, user_id: 103, amount: 300, status: "PAID" },
{ order_id: 4, user_id: 104, amount: 150 } // 无 status
]);
db.orders.createIndex({ status: 1 }, { sparse: true });
db.orders.find({ status: "PAID" });
这里我们注意稀疏索引的特点是如果document有的有status ,有的没有则只对有status的key进行建立索引。
关于SQL优化的部分,在insert ,delete ,update等操作中如果了解业务,可以在语句中添加同步或异步的语句。在操作大量的DML语句时,在MongoDB中是可以选择数据写入的方式的,下面有几种方式案例
1 数据写入并不马上查询,但有大量的数据要写入。
db.orders.insertOne(
{ order_id: 2, user_id: 102, amount: 200, status: "CREATED" },
{ writeConcern: 0 } 异步写入
);
2 数据插入后,马上就要查询到,(主库插入,其他节点查询)
db.orders.updateOne(
{ order_id: 1 },
{ $set: { status: "PAID" } },
{ writeConcern: { w: "majority", j: true } } // 等待磁盘和多数节点确认
);
以此类推,任何的操作都可以通过writeConcern 的设置来满足不同业务对于数据库DML的处理需求。
最后一句是关于聚合操作的部分,聚合操作一直是MongoDB的一个需要解决的问题,常见我们的方案是提前过滤需要过滤的数据。
下面把两种语句的写法拿出来,一个错误的,一个正确的
错误的
db.orders.aggregate([
{ $group: { _id: "$customer_id", total: { $sum: "$amount" } } },
{ $match: { total: { $gt: 1000 } } } // 后过滤,浪费计算
]);
正确的
db.orders.aggregate([
{ $match: { status: "PAID" } }, // 先过滤
{ $group: { _id: "$customer_id", total: { $sum: "$amount" } } },
{ $match: { total: { $gt: 1000 } } } // 再过滤聚合结果
]);
正确的写法,是将project映射的字段,减少无效的数据传输。
对于嵌套数据的优化也有两种写法 一种错误,一种正确。
db.orders.insertMany([
{ order_id: 1, customer_id: 101, items: [{ sku: "A1", qty: 2 }, { sku: "B2", qty: 1 }] },
{ order_id: 2, customer_id: 102, items: [{ sku: "A1", qty: 1 }, { sku: "C3", qty: 5 }] }
]);
错误写法
db.orders.aggregate([
{ $unwind: "$items" }, 先拆全部数组
{ $match: { "items.sku": "A1" } }, // 再过滤
{ $group: { _id: "$items.sku", total_qty: { $sum: "$items.qty" } } }
]);
正确写法
db.orders.aggregate([
{ $project: { customer_id: 1, items: { $filter: { input: "$items", as: "item", cond: { $eq: ["$$item.sku", "A1"] } } } } },
{ $unwind: "$items" }, 只拆符合条件的数组元素
{ $group: { _id: "$items.sku", total_qty: { $sum: "$items.qty" } } }
]);
这里如果有时间类型聚合的大量需求,要在MongoDB中完成,也可以更新到MongoDB 8.0,针对于时间聚合方面,在不改变任何语句的情况下,复杂的时间序列聚合操作速度提升明显,通过block processing 的机制,提高了时间聚合操作的性能。同时对于_id object_id的直接查询,引入了expresspath的查询模式,不再通过查询计划,而是直接访问存储引擎,速度更快。
每种数据库有每种的优化的方法和特性,抓住核心,在增加需要优化的数据库本身的特性,就可以快速扩展,添加新的技能。
微软动手了,联合OpenAI + Azure 云争夺AI服务市场
“当复杂的SQL不再需要特别的优化”,邪修研究PolarDB for PG 列式索引加速复杂SQL运行
“合体吧兄弟们!”——从浪浪山小妖怪看OceanBase国产芯片优化《OceanBase “重如尘埃”之歌》
未知黑客通过SQL SERVER 窃取企业SAP核心数据,影响企业运营
那个MySQL大事务比你稳定,主从延迟低,为什么? Look my eyes! 因为宋利兵宋老师
非“厂商广告”的PolarDB课程:用户共创的新式学习范本--7位同学获奖PolarDB学习之星
说我PG Freezing Boom 讲的一般的那个同学,专帖给你,看看这次可满意
这个 PostgreSQL 让我有资本找老板要 鸡腿 鸭腿 !!
OceanBase Hybrid search 能力测试,平换MySQL的好选择
HyBrid Search 实现价值落地,从真实企业的需求角度分析 !不只谈技术!
OceanBase 光速快递 OB Cloud “MySQL” 给我,Thanks a lot
从“小偷”开始,不会从“强盗”结束 -- IvorySQL 2025 PostgreSQL 生态大会
被骂后的文字--技术人不脱离思维困局,终局是个 “死” ? ! ......
个群2025上半年总结,OB、PolarDB, DBdoctor、爱可生、pigsty、osyun、工作岗位等
从MySQL不行了,到乙方DBA 给狗,狗都不干? 我干呀!
SQL SERVER 2025发布了, China幸亏有信创!
MongoDB 麻烦专业点,不懂可以问,别这么用行吗 ! --TTL
PostgreSQL 新版本就一定好--由培训现象让我做的实验
删除数据“八扇屏” 之 锦门英豪 --我去-BigData!
写了3750万字的我,在2000字的OB白皮书上了一课--记 《OceanBase 社区版在泛互场景的应用案例研究》
疯狂老DBA 和 年轻“网红” 程序员 --火星撞地球-- 谁也不是怂货
和架构师沟通那种“一坨”的系统,推荐只能是OceanBase,Why ?
跟我学OceanBase4.0 --阅读白皮书 (OB分布式优化哪里了提高了速度)
跟我学OceanBase4.0 --阅读白皮书 (4.0优化的核心点是什么)
跟我学OceanBase4.0 --阅读白皮书 (0.5-4.0的架构与之前架构特点)
跟我学OceanBase4.0 --阅读白皮书 (旧的概念害死人呀,更新知识和理念)
MongoDB 相关文章
MongoDB “升级项目” 大型连续剧(4)-- 与开发和架构沟通与扫尾
MongoDB “升级项目” 大型连续剧(3)-- 自动校对代码与注意事项
MongoDB “升级项目” 大型连续剧(2)-- 到底谁是"der"
MongoDB “升级项目” 大型连续剧(1)-- 可“生”可不升
MongoDB 大俗大雅,上来问分片真三俗 -- 4 分什么分
MongoDB 大俗大雅,高端知识讲“庸俗” --3 奇葩数据更新方法
MongoDB 大俗大雅,高端的知识讲“通俗” -- 2 嵌套和引用
MongoDB 大俗大雅,高端的知识讲“低俗” -- 1 什么叫多模
MongoDB 合作考试报销活动 贴附属,MongoDB基础知识速通
MongoDB 使用网上妙招,直接DOWN机---清理表碎片导致的灾祸 (送书活动结束)
MongoDB 2023年度纽约 MongoDB 年度大会话题 -- MongoDB 数据模式与建模
免费PolarDB云原生课程,听课“争”礼品,重塑云上知识,提高专业能力
“PostgreSQL” 高性能主从强一致读写分离,我行,你没戏!
POLARDB 添加字段 “卡” 住---这锅Polar不背
PolarDB 版本差异分析--外人不知道的秘密(谁是绵羊,谁是怪兽)
PolarDB 答题拿-- 飞刀总的书、同款卫衣、T恤,来自杭州的Package(活动结束了)
PolarDB for MySQL 三大核心之一POLARFS 今天扒开它--- 嘛是火
PostgreSQL 无服务 Neon and Aurora 新技术下的新经济模式 (翻译)
“PostgreSQL” 高性能主从强一致读写分离,我行,你没戏!
全世界都在“搞” PostgreSQL ,从Oracle 得到一个“馊主意”开始
PostgreSQL 加索引系统OOM 怨我了--- 不怨你怨谁
PostgreSQL “我怎么就连个数据库都不会建?” --- 你还真不会!
PostgreSQL 稳定性平台 PG中文社区大会--杭州来去匆匆
PostgreSQL 分组查询可以不进行全表扫描吗?速度提高上千倍?
POSTGRESQL --Austindatabaes 历年文章整理
PostgreSQL 查询语句开发写不好是必然,不是PG的锅
MySQL相关文章





