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

Knex事务中批量更新操作耗时逐次递增问题咨询

事务中批量更新耗时递增的原因与优化方案

问题现象

在事务中批量执行更新操作时,日志显示后续更新的耗时逐次增加,单次耗时从129ms开始,每次递增约129ms,最终总耗时达到1745ms。

原代码示例

const updateFuncs = data
        .map(async (item) => {
          const now11 = new Date().getTime()
          let entity = this.removeUnusedKeys(item)
          entity = delUndefinedOfKeys(entity)
          const { id, ...rest } = entity
          const now22 = new Date().getTime()
          if (Object.keys(rest).length !== 0) {
            const query = trx(this.tabName)
              .where({
                id
              })
              .update(rest)
              .then((res) => {
                console.log(new Date().getTime() - now22, `each =======${id}`)
              })
            return query
          }
          return null
        })
        .filter(Boolean)
await Promise.all(updateFuncs)
await trx.commit()

耗时日志

129 each =======10532
259 each =======10533
398 each =======10534
526 each =======10535
651 each =======10536
798 each =======10537
930 each =======10538
1061 each =======10539
1196 each =======10540
1347 each =======10541
1475 each =======10542
1615 each =======10543
1745 each =======10544

原因分析

  1. 计时逻辑的误导:日志中计算的耗时是从now22(实体处理完成的时间)到查询完成的时间,而非单个查询的实际执行时间。由于事务内的更新被数据库串行处理,后续查询需要等待前面的所有查询执行完毕才能开始,因此这个耗时包含了前面所有查询的执行时间总和,导致看起来逐次递增。

  2. 事务内查询的串行执行:为了保证事务的ACID特性(原子性、一致性、隔离性、持久性),多数数据库对同一事务内的多个DML操作不会并行执行,而是按请求顺序排队处理。即使通过Promise.all同时发起所有更新请求,数据库也会逐个执行,造成后续查询的等待时间累加。

解决方案

1. 修正计时逻辑,查看真实执行时间

将计时点移到查询执行前,这样能准确看到单个查询的实际耗时:

const updateFuncs = data
        .map(async (item) => {
          let entity = this.removeUnusedKeys(item)
          entity = delUndefinedOfKeys(entity)
          const { id, ...rest } = entity
          if (Object.keys(rest).length !== 0) {
            const queryStart = new Date().getTime() // 移到查询前计时
            const query = trx(this.tabName)
              .where({ id })
              .update(rest)
              .then((res) => {
                console.log(new Date().getTime() - queryStart, `each =======${id}`)
              })
            return query
          }
          return null
        })
        .filter(Boolean)
await Promise.all(updateFuncs)
await trx.commit()

修正后,你会发现每个查询的实际执行时间基本一致,不会出现递增的情况。

2. 批量更新优化(推荐)

将多个更新合并为一个批量查询,大幅提升性能。以Knex为例,可以使用batchUpdate方法:

// 先整理需要更新的数据
const updateData = data
  .map(item => {
    let entity = this.removeUnusedKeys(item)
    entity = delUndefinedOfKeys(entity)
    const { id, ...rest } = entity
    return Object.keys(rest).length ? { id, ...rest } : null
  })
  .filter(Boolean)

// 执行批量更新
if (updateData.length) {
  await trx(this.tabName)
    .batchUpdate('id', updateData, { chunkSize: 100 }) // chunkSize可根据数据库调整
}
await trx.commit()

批量更新只需与数据库建立一次连接,执行一次SQL语句,性能远优于循环单个更新。

内容的提问来源于stack exchange,提问作者QQ.FE

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 09:16:01