V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
coldmonkeybit
V2EX  ›  Node.js

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

  •  
  •   coldmonkeybit · 2022-11-25 16:36:16 +08:00 · 6349 次点击
    这是一个创建于 729 天前的主题,其中的信息可能已经有所发展或是发生改变。

    一个新项目用 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(),但不知道有没有什么大的影响

    18 条回复    2022-11-27 20:52:02 +08:00
    iwh718
        1
    iwh718  
       2022-11-25 16:39:14 +08:00 via Android
    并发吧。
    coderxy
        2
    coderxy  
       2022-11-25 16:39:17 +08:00
    正确的用法就是这样
    ysc3839
        3
    ysc3839  
       2022-11-25 16:43:34 +08:00
    await 的话是按顺序执行,一个完成后执行下一个。Promise.all 是同时执行三个,然后等三个都完成。如果没有顺序要求的话是没问题的。
    star7th
        4
    star7th  
       2022-11-25 16:45:27 +08:00
    没啥不良影响,你可以这么用。
    第一种 await 的方式顺序执行,一个执行完成再执行另一个。
    第二种方式是,并发执行,等到最后一个结果执行完毕后,再按顺序返回执行结果数据。

    一个是顺序执行,一个是并发执行,当然快了很多。
    coldmonkeybit
        5
    coldmonkeybit  
    OP
       2022-11-25 16:46:15 +08:00
    @ysc3839 对,我就是想到这点,但就是怕有什么我不知道的地方,才上来确认下,谢谢了。
    coldmonkeybit
        6
    coldmonkeybit  
    OP
       2022-11-25 16:46:40 +08:00
    @star7th 明白了,谢谢
    pkoukk
        7
    pkoukk  
       2022-11-25 16:52:51 +08:00   ❤️ 1
    不太一样,业务也许可以接受 order 删除了,item 没有成功删除
    但不一定能接受 item 删除了,order 没有成功删除
    得看你的业务,这种非幂等行为最好还是丢在同个事务里执行
    coldmonkeybit
        8
    coldmonkeybit  
    OP
       2022-11-25 16:59:52 +08:00
    @pkoukk 确实,不过假如场景换成查询的话,这种并发的模式感觉挺好用,比多个表关联查询要省事很多,适合我这种不是一上来就做后端的哈哈
    makelove
        9
    makelove  
       2022-11-25 18:07:55 +08:00
    印象中 mysql 一个 connection 并不能并发查询,因为它并不线程安全
    除非你每个查询都用了不同的 connection ,但这样怎么做事务?
    gouflv
        10
    gouflv  
       2022-11-25 18:29:53 +08:00 via iPhone
    不需要事务的话,随便
    ysc3839
        11
    ysc3839  
       2022-11-25 18:38:30 +08:00
    @makelove 连接库会有处理的吧?假如不支持并发的话,await 的时候另一个请求来了,又去操作数据库,不就出问题了?
    ETiV
        12
    ETiV  
       2022-11-25 19:22:46 +08:00
    可以考虑用 async.queue 控制下并发。

    因为你在访问数据库,所以如果并发量没控制好的话,数据库很容易就被你打卦、成单点故障了。。
    zhennann
        13
    zhennann  
       2022-11-25 19:43:33 +08:00
    1. 如果不考虑事务的话,每个 sql 语句的执行都是从连接池中取一个可用的连接,执行完后又把连接释放,并放回连接池。所以,如果并发语句太多,仍然会等待
    2. 如果 QPS 少的话,在代码内部使用 Promise.all 可以充分利用连接池。如果 QPS 多的话,Promise.all 价值就不大了。因为连接池总是有限的,不是在这等待,就是在那等待
    3. 因此,在业务开发中,考虑到要实现的代码逻辑比较多,都用 Promise.all 做优化,性价比就不高了,还是以提高开发效率优先吧
    stimw
        14
    stimw  
       2022-11-26 03:42:29 +08:00 via iPhone
    stimw
        15
    stimw  
       2022-11-26 03:46:58 +08:00 via iPhone
    @stimw 说明一下,这个提问和楼主问题是有区别的。只有第三个回答( 51 票那个),以及第四个回答的评论区,是跟楼主问题相关的。
    stevezhang
        16
    stevezhang  
       2022-11-26 10:32:45 +08:00
    all 你其中有失败的操作不就寄了
    zyronon
        17
    zyronon  
       2022-11-26 13:29:37 +08:00   ❤️ 1
    用 Promise.allSettled()才能拿到所有返回值
    chenzhe
        18
    chenzhe  
       2022-11-27 20:52:02 +08:00
    @zyronon 学习到了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2822 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 14:04 · PVG 22:04 · LAX 06:04 · JFK 09:04
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.