在MySQL中更新数百万行 -- 何时提交

8 投票
2 回答
3925 浏览
提问于 2025-04-20 07:44

我有一个循环,它要处理几百万个对象。你觉得应该怎么做才能更好地完成这个任务呢?我想了一些方法:

# after each
for item in items:
    cursor.execute()
    conn.commit()

# at the end
for item in items:
    cursor.execute()
conn.commit()

# after N items
for n, item in enumerate(items):
    cursor.execute()
    if n % N == 0:
        conn.commit()
conn.commit()

以上哪种方法效率最高呢?

2 个回答

1

可以说是“最后的那个”,因为你只需一次性执行 BEGINCOMMIT,这就形成了一个独立的事务。这样做从并发的角度来看更简单:基本上这个事务就像在说:“这是我的表,其他人别动。”

如果你多次提交(也就是其他两个解决方案),那么你就会多次执行 BEGINCOMMIT,每次提交后都会开始一个新的事务。这就意味着其他正在进行的数据库操作有更多机会打断你。而且,这些操作本身也需要时间。

不过,你应该进行一个基准测试,模拟一下你的使用场景。我很好奇在某些条件下(比如插入的行数、会话配置、数据类型、使用的索引等),哪种方案会更好。

5

你在问,应该在什么时候提交更改...

  1. 在大操作结束时只提交一次
  2. 在每次更新一行后提交
  3. 每处理N个项目后提交一次。

首先,如果你使用的是MyISAM数据库,那就不用担心这个问题。因为MyISAM不支持事务。

如果你的系统在只提交部分行更改的情况下不会出问题,那你应该选择每处理N个项目后提交一次。这样做的原因是,如果每处理一个项目就提交一次,会让你的处理速度变得非常慢。而在大操作结束时只提交一次,可能会导致你的回滚空间被占满,或者在提交的过程中,其他使用数据库的用户会遇到很慢的情况。

我经历过这种情况无数次。只要N大于20就可以了。

撰写回答