uni-app 聚合操作下 match中添加过滤条件使用or后查询速度大大降低 优化建议

发布于 1周前 作者 zlyuanteng 来自 Uni-App

uni-app 聚合操作下 match中添加过滤条件使用or后查询速度大大降低 优化建议

产品分类:

uniCloud/支付宝小程序云

示例代码:

比如有一个数据库A,在一次请求的基础上需要查询两次,一次按照时间来查询30条数据,一个随机查询30条数据,然后重复请求两次,响应速度大大降低,然后合并在一个后用or,同样也会大大降低查询速度,这种之前在阿里云不会有这个问题,这个问题可以优化一下吗?

let res = await DB.collection('A').aggregate()
.match({
time: command.gt(time),
user: "ok",
})
.lookup({
from: 'user',
let: {
user_id: '$id',
},
pipeline: aggregate.pipeline()
match(command.expr(aggregate.and([
aggregate.eq(['$id', '$$user_id']),
])))
.project({
id: 1,
})
.done(),
as: "data_user",
})
.sample({
size: 30,
})
.end()

===========================================================================

let Res = await DB.collection('A').aggregate()
.match({
user: "ok",
})
.lookup({
from: 'user',
let: {
user_id: '$id',
},
pipeline: aggregate.pipeline()
match(command.expr(aggregate.and([
aggregate.eq(['$id', '$$user_id']),
])))
.project({
id: 1,
})
.done(),
as: "data_user",
})
.sample({
size: 30,
})
.end()

操作步骤:

如上面所说

预期结果:

速度提升

实际结果:

没有提升

bug描述:

聚合操作的下,在match中添加过滤条件时,使用了or后,查询速度大大降低,都是5、6秒后才会出结果,删除or只保留简单的过滤条件后变成一秒出结果,请问一下这能优化一下吗


5 回复

理论上没有不会有这么大的区别。有具体的代码或者截图吗,可以发来看看


添加索引试下。

在uni-app中,当你使用聚合操作并在match阶段添加过滤条件时,如果使用了$or操作,确实可能会导致查询速度变慢。这主要是因为$or操作需要数据库扫描多个索引或进行全表扫描来满足条件,从而增加了查询的复杂性。

为了优化这种情况,你可以考虑以下几种方法:

  1. 索引优化: 确保你的数据库字段已经建立了合适的索引。对于$or中的每个条件,如果可能的话,都应该尽量利用索引来加速查询。

  2. 减少查询字段: 在match阶段之后,使用project阶段只选择你需要的字段,减少数据传输和处理的开销。

  3. 使用复合索引: 如果$or中的条件是多个字段的组合,考虑创建复合索引。复合索引可以显著提高多个字段组合查询的速度。

  4. 重构查询: 如果可能,尝试重构查询逻辑,避免使用$or,或者将其拆分成多个单独的查询,然后在应用层合并结果。

以下是一个使用MongoDB(假设你的uni-app后端使用的是MongoDB)的示例代码,展示了如何优化包含$or的查询:

// 假设我们有一个集合users,并且需要查询满足以下条件的文档:
// 年龄大于30或者城市是'Beijing'

// 优化前:直接使用$or
db.users.aggregate([
  {
    $match: {
      $or: [
        { age: { $gt: 30 } },
        { city: 'Beijing' }
      ]
    }
  },
  {
    $project: {
      _id: 0,
      name: 1,
      age: 1,
      city: 1
    }
  }
]);

// 优化后:创建复合索引并尝试拆分查询(如果逻辑允许)
// 首先,创建复合索引(如果尚未创建)
db.users.createIndex({ age: 1, city: 1 });

// 然后,考虑将查询拆分为两个单独的查询(如果业务逻辑允许)
// 在应用层合并结果
const query1 = db.users.aggregate([
  {
    $match: { age: { $gt: 30 } }
  },
  {
    $project: {
      _id: 0,
      name: 1,
      age: 1,
      city: 1
    }
  }
]);

const query2 = db.users.aggregate([
  {
    $match: { city: 'Beijing' }
  },
  {
    $project: {
      _id: 0,
      name: 1,
      age: 1,
      city: 1
    }
  }
]);

// 在应用层,你可以使用Promise.all或其他异步处理方法来合并这两个查询的结果
Promise.all([query1.toArray(), query2.toArray()])
  .then(([results1, results2]) => {
    const finalResults = results1.concat(results2);
    // 处理finalResults
  })
  .catch(error => {
    // 处理错误
  });

请注意,以上代码示例是基于MongoDB的,如果你的uni-app后端使用的是其他数据库,可能需要调整查询语法和索引创建方式。

回到顶部