收藏
回答

急!关于云开发数据库联表复杂查询超时失败问题,该如何优化?

您好,我公司开发的婚恋平台,由于业务需要使用了比较复杂的【lookup联表查询】,近期数据增多后,经常出现因查询超时失败的糟糕情况,不知道如何优化了!

如图,业务使用了两个表,一个是约会信息表meet,一个是用户信息表user,我们需要提供对用户信息、约会信息的筛选查询、排序功能,需要对两个表的信息进行联合复杂查询、排序。现在老是出错,不知道怎么优化了,求大神帮忙看看!

查询代码如下:

async function meet_list(event) {
  var match = { sta: 1 };
  var sort = { upT: -1 };
  if (event.region_code.length == 1) {
    match.zip0 = event.region_code[0] * 1;//同省
  }
  else if (event.region_code.length > 1) {
    match.zip1 = event.region_code[1] * 1;//同城
  }
  if (event.sex > 0) {
    match.sex = event.sex * 1;
  }
  if (event.edu >= 0) {
    match.edu = event.edu * 1;
  }
  if (event.mar >= 0) {
    match.mar = event.mar * 1;
  }

  if (event.more != '') {
    switch (event.more) {
      case 'sm':
        match.sm = 1;
        break;
      case 'club':
        let nowTs = Date.parse(new Date()) / 1000;
        match.club = _.gt(nowTs);
        break;
      case 'vip':
        match.vip = _.gt(100);
        break;
      case 'fn':
        match.fn = _.gt(0);
        break;
      case 'face':
        sort = { face: -1 };
        break;
      case 'ker':
        sort = { ker: -1 };
        break;
      case 'kp':
        sort = { kp: -1 };
        break;
      case 'hot':
        sort = { post: -1 };
        break;
      case 'nx':
        sort = { nx: -1 };
        break;
      case 'new':
        sort = { _id: -1 };
        break;
      case 'xqx1':
        match.sex = 1;
        match.xqx = 1;
        break;
      case 'xqx2':
        match.sex = 2;
        match.xqx = 2;
        break;
    }
  }
  //年龄筛选
  if (event.age.length > 1) {
    match.birt = _.and(_.lte(event.age[0] * 1), _.gte(event.age[1] * 1));
  }
  var $ = db.command.aggregate
  var commad = db.collection('meet').aggregate();
  if (event.geo.length == 2) {
    commad = commad.geoNear({
      distanceField: 'distance', // 输出的每个记录中 distance 即是与给定点的距离
      spherical: true,
      distanceMultiplier: 6378137,//这样算出来的才是米
      near: db.Geo.Point(event.geo[0], event.geo[1])
    })
    sort = { distance: 1, _id: -1 };
  }
  var res = await commad
    .lookup({
      from: 'user',
      localField: '_openid',
      foreignField: '_id',
      as: 'user',
    })
    .replaceRoot({
      newRoot: $.mergeObjects([$.arrayElemAt(['$user', 0]), '$$ROOT'])
    })
    .match(match)
    .project({
      name: 1,
      sex: 1,
      birt: 1,
      club: 1,
      sm: 1,
      vip: 1,
      face: 1,
      edu: 1,
      ker: 1,
      kp: 1,
      _id: 1,
      _openid: 1,
      type1,
      tit: 1,
      reg: 1,
      ht: 1,
      img: 1,
      job: 1,
      idea: 1,
      post: 1,
      upT: 1,
      nx: 1,
      cher: 1,
      distance: 1
    })
    .sort(sort)
    .skip(event.offset)
    .limit(event.limit)
    .end()
  return res.list;
}


已参考这个进行了索引优化,但还是不行(可能是我对索引的理解不够透切)

https://developers.weixin.qq.com/community/minihome/article/doc/0008cc5e8cc2a8d5789a981bf55c13

相关配置,也已调成最大化

最后一次编辑于  2022-06-20
回答关注问题邀请回答
收藏

1 个回答

  • 跨商通
    跨商通
    2022-06-21

    geoNear阶段之后,就match,再limit,这样之后lookup面对的数据量就只是limit条,而不是整个数据。


    2022-06-21
    有用
    回复 9
    • 小树
      小树
      2022-06-21
      match的条件,是两个表的字段都用到呢?
      2022-06-21
      回复
    • 跨商通
      跨商通
      2022-06-21回复小树
      方法一:先match掉meet表的字段再lookup;
      方法二:meet表中添加match需要的字段,不仅仅是openid;
      方法三:就一个表meet,不需要lookup,用户信息完全放在meet中。
      2022-06-21
      回复
    • 小树
      小树
      2022-06-21
      方法二,没理解。目前在考虑做冗余设计,也就是方法三,把user表要用到的字段信息放入meet表中,在查询中完全去掉user表,不需要lookup
      2022-06-21
      回复
    • 跨商通
      跨商通
      2022-06-21回复小树
      方法二:比如match只需要user中的age,不需要其他字段,那你meet中加上age即可;
      2022-06-21
      回复
    • 跨商通
      跨商通
      2022-06-21回复小树
      另外,就你当前的方案,geoNear之后,match掉distance都足够优化了。你用geoNear不就是搜附近吗?distance小于5公里,就能筛掉90%的数据,你这样全表匹配,没必要啊。
      2022-06-21
      回复
    查看更多(4)
登录 后发表内容