You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB匹配部分手机号数组查询文档的性能问题咨询

关于MongoDB手机号后9位匹配查询的性能与生产可用性分析

你最初设想的$in同时传入数值数组和统一正则的写法无法正常生效,MongoDB不支持这种混合匹配的逻辑,只能像你测试的那样把每个后9位转成后缀正则放到$in中。

现有实现的性能问题

  • 无法命中普通索引:结尾匹配的正则/xxx$/没有固定前缀字符,普通单字段索引对这类查询完全失效,数据量较大时会触发全表扫描,查询延迟会随用户量级增长线性上升
  • 多正则匹配开销高:$in中传入N个正则表达式时,每一条扫描到的文档都需要逐一匹配N次正则,当上传的联系人数组长度较大(比如超过50)时,CPU开销会显著上升,高并发场景下很容易出现请求超时

生产环境使用建议

如果你的业务满足以下所有条件,可以临时使用该方案上线:

  • 用户总规模低于10万
  • 单次请求上传的联系人数组长度不超过30
  • 该接口的QPS低于10

如果不符合以上条件,不建议直接在生产环境使用该方案,推荐使用更优化的实现方式。

推荐优化方案

方案1:冗余存储后9位字段(最优)

写入用户数据时,额外冗余存储一个phoneLast9字段,值为手机号后9位,为该字段建立普通索引。查询时直接使用以下语句即可走索引查询,性能提升10倍以上:

usersContacts = [123456789, 987654321, 123443212,...]
db.users.find({
  phoneLast9: { $in: usersContacts }
})

该方案改造成本极低,查询性能最优,是生产环境的首选方案。

方案2:创建计算字段索引(无需修改存量写入逻辑)

如果不方便修改存量数据的写入逻辑,可以在MongoDB 4.4及以上版本中创建计算字段索引,直接对手机号后9位的计算结果建索引:

// 创建计算索引
db.users.createIndex({
  "$expr": {
    $substrCP: [ "$phoneNumStr", { $subtract: [ { $strLenCP: "$phoneNumStr" }, 9 ] }, 9 ]
  }
}, {name: "phone_last9_idx"})

// 查询时使用$expr匹配
db.users.find({
  $expr: {
    $in: [
      { $substrCP: [ "$phoneNumStr", { $subtract: [ { $strLenCP: "$phoneNumStr" }, 9 ] }, 9 ] },
      usersContacts
    ]
  }
})

该方案无需修改现有写入逻辑,查询也可以命中索引,性能接近冗余字段方案。

内容的提问来源于stack exchange,提问作者cjd

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 14:54:01