知其然,知其所以然
MongoDB 2026-10-12

skip 大偏移的代价与范围分页

实测 skip 大偏移的代价与范围分页:50 万个文档上 skip 400,000 要 74 ms、检查 400,020 个键,范围分页每页恒定 0.2~0.4 ms;SKIP 在 FETCH 之下,只读索引键不读文档;排序键不唯一要带 _id 平局打破;翻页期间有新数据时 skip 重复 10 条而范围分页不重复;count 的两种代价。

MongoDB 分页 skip 范围分页 游标 性能 真实验证 动画演示
MongoDB 2026-10-12

$in 的元素数量对查询的影响

实测 $in 元素数量对查询的影响:S 从 1 到 100,000 耗时 0.2 ms 到 126 ms(每个值约 1.4 μs,检查的键约是返回数的 2 倍);规划耗时在 S=100,000 时达 4.4 ms;结果按索引键顺序返回、重复值去重;无索引时全表扫描 79 到 200 ms;$in 与 $or 接近;150 万个整数的 $in 超出 16 MB 上限。

MongoDB $in 索引 查询 性能 真实验证 动画演示
MongoDB 2026-10-12

count、countDocuments、estimatedDocumentCount 的差别

实测 count 的三种写法:estimatedDocumentCount 读元数据只要 0.2 ms,countDocuments({}) 要数 100 万个文档 97 ms,带索引的条件走 COUNT_SCAN(1.4 ms)、无索引则 COLLSCAN(110 ms);kill -9 重启后 estimatedDocumentCount 是 0,要 validate 才修正;带 limit 的 count 提前停止。

MongoDB count countDocuments estimatedDocumentCount 元数据 真实验证 动画演示
MongoDB 2026-10-12

索引占多大:前缀压缩与字段长度

实测索引占多大:20 万个文档上 12 个字段的索引,每条目从 5.4 字节(枚举)到 150.6 字节(128 字符随机串),全部索引 79.8 MB 比 68.2 MB 数据还大;顺序递增的字符串比随机的小 3.4 倍(前缀压缩);关掉前缀压缩后膨胀 3.6~5.0 倍;随机字符串每个字符约 1.14 字节;线性增长。

MongoDB 索引大小 前缀压缩 字段长度 WiredTiger 真实验证 动画演示
MongoDB 2026-10-12

$lookup:有无索引的执行差别

实测 $lookup 有无索引的差别:外键有索引是 IndexedLoopJoin,1,000 条订单 3.9 ms;没有索引是 NestedLoopJoin,2,367 ms(约 600 倍),10,000 条要 24 秒;建索引后立刻恢复;let / pipeline 形式慢约 5 倍;$lookup 结果超过 16 MiB 可以返回但不能 $out。

MongoDB $lookup 索引 连接 IndexedLoopJoin NestedLoopJoin 真实验证 动画演示
MongoDB 2026-10-12

数组更新操作符:$push、$pull、$addToSet、$[]

实测数组更新操作符:$push 的 $each / $position / $sort / $slice,$addToSet / $pull / $pullAll / $pop 的语义;位置操作符 $、$[]、$[<id>] 加 arrayFilters;对非数组字段 $push 的报错;$addToSet 对子文档字段顺序敏感;8 线程各 100 次 $push 全部保留(800),读-改-写只剩 153。

MongoDB 数组更新 $push $pull $addToSet 位置操作符 arrayFilters 真实验证 动画演示
MongoDB 2026-10-12

并发 upsert 与唯一索引:E11000 从哪来

实测并发 upsert:没有唯一索引时 16 线程 300 轮产生 632 个文档(227 个 k 重复);有唯一索引时文档数正好 300,服务端自动重试所以客户端看不到 E11000;条件不含唯一键时 E11000 会露给应用;捕获后改普通更新可行;findOneAndUpdate + $inc 取号无重复。

MongoDB upsert 并发 唯一索引 E11000 findOneAndUpdate 真实验证 动画演示
MongoDB 2026-10-12

findAndModify 做任务队列

实测用 findOneAndUpdate 做任务队列:8 个 worker 原子领取 2,000 个任务零重复(7,462 个/秒);先 find 再 update 的做法有 6,377 个任务被重复领取;带条件 update 没有重复但失败 6,223 次、慢 8 倍;按优先级领取、队列索引(0.1 对 17 ms)、租约清扫崩溃的 worker。

MongoDB findAndModify 任务队列 原子领取 租约 真实验证 动画演示
MongoDB 2026-10-12

bulkWrite 的 ordered 与 unordered

实测 bulkWrite 的 ordered 与 unordered:ordered 在第一个错误处停止(nInserted 4),unordered 跳过错误继续(nInserted 6,4 个错误一起返回);混合操作的顺序在 unordered 下不再保证;25 万个文档拆成 3 条命令(maxWriteBatchSize 100,000);单节点上耗时几乎一样。

MongoDB bulkWrite ordered unordered 批量写入 真实验证 动画演示
MongoDB 2026-10-12

写关注 w:1、majority、j:true 的耗时对比

实测写关注的延迟:3 节点副本集上 w:1 0.2 ms,w:2 / w:3 0.6 ms,j:true 与 w:majority 约 4 ms(要等 journal 落盘);secondary 挂掉后 w:majority 仍成功、w:3 超时报 code 64 但写入已生效;只剩 1 个节点 primary 降级;w:0 不报错;写关注的设置位置与优先级。

MongoDB 写关注 writeConcern w:majority journal 副本集 真实验证 动画演示
MongoDB 2026-10-12

多文档事务:快照隔离与 WriteConflict

实测多文档事务:事务内读到开始时的快照,事务外的提交看不到;事务之间的写冲突 4 ms 内报 WriteConflict(code 112,带 TransientTransactionError),事务外的写入则等待事务结束(等了 1,526 ms);16 线程 with_transaction 计数 1600 次一个不丢(重试 1,492 次);快照隔离下的写偏斜让在岗人数变成 0。

MongoDB 事务 快照隔离 WriteConflict 写偏斜 with_transaction 真实验证 动画演示
MongoDB 2026-10-12

事务 60 秒上限:到点之后发生什么

实测事务的生命周期上限:默认 60 秒;事务外的写入会等到过期事务被中止(上限调到 5 秒时等了 5,357 ms);过期后继续操作与 commit 都报 251 NoSuchTransaction 且修改回滚;生命周期不因有操作续期;中止不是准点——默认 60 秒的事务 70 秒时仍能提交成功,89 秒才被清理。

MongoDB 事务 transactionLifetimeLimitSeconds NoSuchTransaction 超时 真实验证 动画演示
京ICP备2026067502号-1京公网安备11010502063487号