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

Schema 校验:validationLevel 与 validationAction 的区别

实测 Schema 校验:121 错误里 errInfo.details 逐条说明哪条规则没通过;validationAction 为 warn 时照样写入并在日志里记警告;validationLevel 的 strict 与 moderate 对不合法的老文档的区别;bypassDocumentValidation 与 off;$expr 校验器;insertMany 在 ordered 与 unordered 下的行为。

MongoDB Schema校验 jsonSchema validationLevel validationAction 真实验证 动画演示
MongoDB 2026-10-12

collation:大小写不敏感比较的代价

实测 collation:默认二进制比较,strength 2 忽略大小写、strength 1 连重音也忽略,numericOrdering 与 zh 拼音排序;collation 查询用不上不带 collation 的索引(全表检查 200,000 个文档),建同 collation 的索引后只检查 1 个;正则 /i 比全表 collation 更慢;集合级默认 collation 与索引变大 17%。

MongoDB collation 大小写 索引 排序 真实验证 动画演示
爬虫工程 2026-10-12

线程池与 asyncio:抓取吞吐在什么并发量下拉开差距

在本机测试服务器(每个请求停 0.1 秒)上对比线程池 requests 与 asyncio aiohttp:并发 10 到 100 时都紧贴理论下限,并发 200 时 698 ms 对 615 ms;无延迟时每请求 0.331 ms 对 0.109 ms;并发 200 的峰值内存比起点多 18.8 MiB 对 3.3 MiB。

爬虫 并发 线程池 asyncio aiohttp requests 吞吐 内存 Python 真实验证 动画演示
爬虫工程 2026-10-12

asyncio 信号量限制并发

实测 asyncio 信号量限制爬虫并发:Semaphore(N) 让服务器看到的并发峰值恰好是 N;但只包住 session.get() 而不包住读取响应体时,Semaphore(5) 的实际并发是 50;TCPConnector(limit=10) 加 total 超时让 200 个请求中 110 个超时,改用 Semaphore 排队则 0 个;20 万个任务 gather 要 310.8 MiB,worker 加队列 23.5 MiB。

爬虫 asyncio Semaphore aiohttp 并发控制 TCPConnector 超时 Python 真实验证 动画演示
MongoDB 2026-10-12

explain 的三种模式:同一条查询看到的信息有什么不同

同一条查询在 explain 的三种模式下看到的信息:queryPlanner 只选计划不执行,executionStats 执行并给出键数、文档数和每个阶段的 works,allPlansExecution 再给出落选计划的试跑统计;update / delete 的 explain 不修改数据;aggregate 的 pipeline 被整个下推并成为覆盖查询。

MongoDB explain queryPlanner executionStats allPlansExecution 真实验证 动画演示
MongoDB 2026-10-12

复合索引字段顺序:等值、排序、范围(ESR)实测

实测复合索引字段顺序(等值、排序、范围):有 limit 20 时 E-S-R 只检查 195 个键最快,不 limit 时 E-S-R 要扫 60,001 个键而 E-R-S 只要 6000 个,反而 E-R-S 更快;优化器无 limit 时仍选了 E-S-R;范围换成等值后等值字段全放前面才是最优。

MongoDB 复合索引 ESR 排序 范围查询 explain 真实验证 动画演示
爬虫工程 2026-10-12

aiohttp 的 limit 与 limit_per_host

实测 aiohttp 的 TCPConnector:默认 limit=100、limit_per_host=0,对单个站点最多同时开 100 条连接;limit 是总数上限、limit_per_host 是每个主机的上限,两个都设时更紧的生效;“主机”按主机名区分(4 个域名指向同一台服务器时对方看到 20 个并发);多个 ClientSession 的 limit 会叠加(3 个会话峰值 30)。

爬虫 aiohttp TCPConnector limit limit_per_host 并发控制 ClientSession Python 真实验证 动画演示
MongoDB 2026-10-12

覆盖查询:totalDocsExamined 怎么变成 0

实测覆盖查询:投影去掉 _id 且字段都在索引里时 totalDocsExamined 为 0;带 _id、取索引外字段、条件里有索引外字段、数组(multikey)字段都要 FETCH;把 _id 放进索引后带 _id 也能覆盖;count 与 $group 也能覆盖。

MongoDB 覆盖查询 索引 explain totalDocsExamined 真实验证 动画演示
爬虫工程 2026-10-12

事件循环里的阻塞调用:解析 HTML 把整个爬虫卡住多久

用心跳任务测 asyncio 事件循环被卡的时间:20 个页面抓完后直接在协程里用 lxml 解析,事件循环最大延迟 1293 ms;放进线程池后降到 15 ms 但总耗时几乎不变(1518 ms),进程池才真正并行(557 ms);协程里直接 requests.get 让 10 个“并发”请求变成串行(1079 ms,服务器峰值 1)。

爬虫 asyncio 事件循环 阻塞调用 lxml run_in_executor 进程池 Python 真实验证 动画演示
MongoDB 2026-10-12

多键索引:数组字段会生成多少条索引条目

实测多键索引:数组每个元素一条索引条目(空数组、缺失、标量各 1 条,同一文档内重复元素去重),条目数和索引大小随数组长度线性增长(100 个元素时每个文档 884 字节),$elemMatch 比普通条件界限更紧,写入代价随元素数线性增长。

MongoDB 多键索引 multikey 数组 索引条目 真实验证 动画演示
MongoDB 2026-10-12

两个数组字段的复合索引为什么报错

实测两个数组字段的复合索引:同一文档里最多一个被索引字段是数组,两个都是数组时插入、更新报 171(cannot index parallel arrays),已有这种文档时建索引失败;同一数组的两个子字段不算并行;拆成单字段索引或展开成子文档数组两种办法的检查键数对比。

MongoDB 并行数组 复合索引 multikey CannotIndexParallelArrays 真实验证 动画演示
爬虫工程 2026-10-12

解析放进进程池:什么时候值得

实测把 HTML 解析放进进程池:池冷启动 83 ms、预热后一个任务来回 0.141 ms;6 KB 到 2.5 MB 的页面 8 个进程都比直接解析快 5.3–6.2 倍,8 个线程基本不加速;传输页面的成本远小于解析;lxml 树不能返回;map 的 chunksize=1 只快 1.29 倍,批量后 6.15 倍。

爬虫 进程池 ProcessPoolExecutor lxml 解析 chunksize GIL Python 真实验证 动画演示
京ICP备2026067502号-1京公网安备11010502063487号