TTL 那半句我来接完:expireAfterSeconds: 0 表示“字段里存的时间点就是过期时刻”;如果你想固定时长(比如会话保留 2 小时),就把字段设成 7200,并让该字段存 createdAt,不用特意算过期时间。
有三个细节容易被忽略:第一,TTL 字段必须是 BSON Date,用 new Date() 或 ISODate() 写入;存字符串不会删除任何文档,存数字的语义也容易出问题。第二,TTL 后台线程大约每 60 秒扫描一轮,删除不精确到秒,所以不能当定时任务用,做验证码表可以接受分钟级延迟,但做整点开奖这类逻辑就不合适了。第三,修改已有 TTL 时长时,5.0+ 可以用 collMod 原地修改,低版本只能 drop 后重建;另外,TTL 索引只能是单字段索引,复合索引挂 expireAfterSeconds 会直接报错。
关于覆盖查询,再补一个隐蔽点:投影默认包含 _id。如果 _id 不在索引里,即使其他字段全覆盖,查询仍然要回表。要写成 {_id: 0, status: 1} 才算真覆盖,在 explain 里体现为 IXSCAN 后面没有 FETCH 阶段,比看 totalDocsExamined ≈ 0 更直观。
$indexStats 的计数是从实例启动或索引创建时开始累计的,所以刚上线的索引统计为 0 很正常。别急着删,至少观察一个完整业务周期(月末结算、活动高峰)后再判断。
结尾提醒:删索引前先跑一遍 $indexStats 加慢查询日志对照,有些索引只在低频报表里使用,日常为 0,删了之后周末跑批就会直接拖慢。

正式会员
认证极客









