Nodejs后端中,请教一下,在 node 后端里面大量通过 Promise.all 来查询数据库有什么影响吗

发布于 1周前 作者 phonegap100 来自 nodejs/Nestjs

Nodejs后端中,请教一下,在 node 后端里面大量通过 Promise.all 来查询数据库有什么影响吗

一个新项目用 node 做后端,前段时间看到一个删除接口需要操作三张表,大概长这样:

async delete(){
	await order.delete();
    await item.delete();
    await history.delete();
}

然后这个时候从前端调用接口响应时间差不多是 600ms (测试库部署在良心云的便宜实例 docker 上所以比较慢)
由于这几个调用之间没有关联,所以尝试了一下使用 Promise.all() 来提交:

async delete(){
  	const asyncRes = await Promise.all([
            	order.delete(),
          	item.delete(),
          	history.delete(),
    ])
}

然后发现响应时间居然直接变成 180ms 了,居然快了这么多。
所以想着有时间就把所有类似的没有关联的请求都换成 all(),但不知道有没有什么大的影响


19 回复

并发吧。


正确的用法就是这样

await 的话是按顺序执行,一个完成后执行下一个。Promise.all 是同时执行三个,然后等三个都完成。如果没有顺序要求的话是没问题的。

没啥不良影响,你可以这么用。
第一种 await 的方式顺序执行,一个执行完成再执行另一个。
第二种方式是,并发执行,等到最后一个结果执行完毕后,再按顺序返回执行结果数据。

一个是顺序执行,一个是并发执行,当然快了很多。

对,我就是想到这点,但就是怕有什么我不知道的地方,才上来确认下,谢谢了。

明白了,谢谢

不太一样,业务也许可以接受 order 删除了,item 没有成功删除
但不一定能接受 item 删除了,order 没有成功删除
得看你的业务,这种非幂等行为最好还是丢在同个事务里执行

确实,不过假如场景换成查询的话,这种并发的模式感觉挺好用,比多个表关联查询要省事很多,适合我这种不是一上来就做后端的哈哈

印象中 mysql 一个 connection 并不能并发查询,因为它并不线程安全
除非你每个查询都用了不同的 connection ,但这样怎么做事务?

不需要事务的话,随便

连接库会有处理的吧?假如不支持并发的话,await 的时候另一个请求来了,又去操作数据库,不就出问题了?

可以考虑用 async.queue 控制下并发。

因为你在访问数据库,所以如果并发量没控制好的话,数据库很容易就被你打卦、成单点故障了。。

  1. 如果不考虑事务的话,每个 sql 语句的执行都是从连接池中取一个可用的连接,执行完后又把连接释放,并放回连接池。所以,如果并发语句太多,仍然会等待
    2. 如果 QPS 少的话,在代码内部使用 Promise.all 可以充分利用连接池。如果 QPS 多的话,Promise.all 价值就不大了。因为连接池总是有限的,不是在这等待,就是在那等待
    3. 因此,在业务开发中,考虑到要实现的代码逻辑比较多,都用 Promise.all 做优化,性价比就不高了,还是以提高开发效率优先吧

说明一下,这个提问和楼主问题是有区别的。只有第三个回答( 51 票那个),以及第四个回答的评论区,是跟楼主问题相关的。

all 你其中有失败的操作不就寄了

用 Promise.allSettled()才能拿到所有返回值

学习到了。

在Node.js后端中,使用Promise.all来并行处理多个数据库查询确实有其优势,比如可以显著减少总的查询时间,尤其是在这些查询之间不存在依赖关系时。然而,它也可能带来一些潜在的问题:

  1. 资源消耗:并行执行多个查询会消耗更多的数据库连接和服务器资源。如果查询数量过大,可能会导致数据库连接池耗尽,影响其他服务的正常运行。

  2. 错误处理Promise.all会等待所有Promise完成,如果其中一个Promise失败,整个Promise.all会立即被拒绝。因此,需要妥善处理错误,避免因为一个查询失败而影响整个流程。

  3. 代码可读性:过多使用Promise.all可能会使代码变得复杂和难以维护,特别是当查询逻辑变得复杂时。

下面是一个简单的示例,展示了如何使用Promise.all进行多个数据库查询,并处理错误:

const db = require('your-database-module');

const queries = [
  db.query('SELECT * FROM table1'),
  db.query('SELECT * FROM table2'),
  // 更多查询...
];

Promise.all(queries)
  .then(results => {
    // 处理所有查询结果
    console.log(results);
  })
  .catch(error => {
    // 处理错误
    console.error('One or more queries failed:', error);
  });

总之,虽然Promise.all可以优化查询性能,但在使用时需要注意资源消耗、错误处理以及代码的可读性和可维护性。如果查询数量过大,可以考虑分批处理或使用其他并发控制策略。

回到顶部