实测 TTL 索引的过期时机:5 秒过期的文档要等到每 60 秒运行一次的 TTL 线程(实测 59.0 s 和 119.2 s)才被删;只有 BSON 日期(或日期数组)会过期;expireAfterSeconds 为 0 配合未来时间可让每个文档自己定过期时刻;collMod 在线改过期时间;20 万个过期文档一轮删完。
实测 9.0.2 的时序集合:底层 system.buckets 不能再直接访问,用 rawData 读到 3 个传感器各 400 个测量只占 3 个 bucket;bucket 文档按列存放、带 min/max/count;每个 bucket 最多 1000 个测量;合成数据占盘只有普通集合的 2%;默认索引与 update/delete 的限制。
实测 MongoDB 视图:只是 system.views 里存下来的一条 pipeline,每次查询重新执行,底层数据一改视图立刻变化;视图没有自己的索引,过滤条件能前移到 $group 之前时走底层索引(150 个文档),在聚合结果上则全表扫描(3000 个);视图只读、深度上限 20、底层集合删除后查询为空、collMod 可以改 pipeline。
实测 Schema 校验:121 错误里 errInfo.details 逐条说明哪条规则没通过;validationAction 为 warn 时照样写入并在日志里记警告;validationLevel 的 strict 与 moderate 对不合法的老文档的区别;bypassDocumentValidation 与 off;$expr 校验器;insertMany 在 ordered 与 unordered 下的行为。
实测 collation:默认二进制比较,strength 2 忽略大小写、strength 1 连重音也忽略,numericOrdering 与 zh 拼音排序;collation 查询用不上不带 collation 的索引(全表检查 200,000 个文档),建同 collation 的索引后只检查 1 个;正则 /i 比全表 collation 更慢;集合级默认 collation 与索引变大 17%。
同一条查询在 explain 的三种模式下看到的信息:queryPlanner 只选计划不执行,executionStats 执行并给出键数、文档数和每个阶段的 works,allPlansExecution 再给出落选计划的试跑统计;update / delete 的 explain 不修改数据;aggregate 的 pipeline 被整个下推并成为覆盖查询。
实测复合索引字段顺序(等值、排序、范围):有 limit 20 时 E-S-R 只检查 195 个键最快,不 limit 时 E-S-R 要扫 60,001 个键而 E-R-S 只要 6000 个,反而 E-R-S 更快;优化器无 limit 时仍选了 E-S-R;范围换成等值后等值字段全放前面才是最优。
实测覆盖查询:投影去掉 _id 且字段都在索引里时 totalDocsExamined 为 0;带 _id、取索引外字段、条件里有索引外字段、数组(multikey)字段都要 FETCH;把 _id 放进索引后带 _id 也能覆盖;count 与 $group 也能覆盖。
实测多键索引:数组每个元素一条索引条目(空数组、缺失、标量各 1 条,同一文档内重复元素去重),条目数和索引大小随数组长度线性增长(100 个元素时每个文档 884 字节),$elemMatch 比普通条件界限更紧,写入代价随元素数线性增长。
实测两个数组字段的复合索引:同一文档里最多一个被索引字段是数组,两个都是数组时插入、更新报 171(cannot index parallel arrays),已有这种文档时建索引失败;同一数组的两个子字段不算并行;拆成单字段索引或展开成子文档数组两种办法的检查键数对比。
实测稀疏索引与部分索引:稀疏索引收录字段存在的文档(显式 null 算存在),用 hint 或排序时会漏掉缺失的;部分索引只收录满足过滤条件的文档,体积小得多(24,576 对 155,648 字节),查询必须蕴含过滤条件才能用;软删除场景的唯一部分索引;过滤条件的限制($ne 不行,$or 可以)。
实测唯一索引遇到 null 和缺失字段:缺失按 null 算,第二个缺失或 null 的文档就报 E11000;唯一加 sparse 允许任意多个缺失但显式 null 仍然冲突;唯一加部分索引(字符串 email)缺失和 null 都不限;复合索引逐字段按 null;已有重复数据时建索引失败及找重复的办法。