15

我有一个进程查询表中PROCESS_IND='N'的记录,进行一些处理,然后将其更新PROCESS_IND为'Y'。

我想允许这个进程的多个实例运行,但不知道避免并发问题的最佳实践是什么。

我应该从哪里开始?

4

5 回答 5

12

我使用的模式如下:

  • 创建列“lockedby”和“locktime”,它们分别是线程/进程/机器 ID 和时间戳(在多台机器之间拆分处理时需要机器 ID)
  • 每个任务都会执行一个查询,例如:

    UPDATE taskstable SET lockedby=(my id), locktime=now() WHERE lockedby IS NULL ORDER BY ID LIMIT 10

其中 10 是“批量大小”。

  • 然后每个任务执行一个 SELECT 来找出它“锁定”了哪些行以进行处理,并处理那些
  • 每行完成后,将lockedby和locktime设置回NULL
  • 所有这些都是在一个循环中完成的,尽可能多的批次。
  • cron 作业或计划任务会定期重置锁定时间过长的任何行的“lockedby”,因为它们可能是由已挂起或崩溃的任务完成的。然后会有人来接他们

LIMIT 10 是特定于 MySQL 的,但其他数据库也有等价物。ORDER BY 是导入以避免查询是不确定的。

于 2009-02-20T08:46:00.433 回答
5

尽管我理解我的意图,但我不同意立即进行行级锁定。这将减少您的响应时间,实际上可能会使您的情况变得更糟。如果在测试之后您发现 APL 的并发问题,您应该首先迭代移动到“数据页”锁定!

要真正正确地回答这个问题,需要有关表结构和所涉及的索引的更多信息,但需要进一步解释。

DOL,数据行锁定比所有页面/页面级锁定使用更多的锁定。管理所有锁的开销以及由于在缓存中请求更多锁结构而导致的可用内存减少将降低性能并抵消通过转向更多并发方法可能获得的任何收益。

测试您的方法,而不首先在 APL 上移动(所有页面锁定“默认”),然后如果发现问题移动到 DOL(首先是数据页,然后是数据行)。请记住,当您将表切换到 DOL 时,该表上的所有响应都会变得稍差,该表使用更多空间并且该表变得更容易出现碎片,需要定期维护。

所以简而言之,不要直接转移到数据行,首先尝试你的并发方法,然后如果有问题,首先使用数据页锁定,然后是最后的数据行。

于 2009-02-19T11:19:39.570 回答
2

您应该row level locking在桌子上启用:

CREATE TABLE mytable (...) LOCK DATAROWS

那么你:

  • 开始交易
  • 使用选项选择您的行FOR UPDATE(这将锁定它)
  • 做你想做的。

在事务结束之前,没有其他进程可以对这一行做任何事情。

PS有人提到使用LOCK DATAROWS.

是的,有开销,但对于这样的桌子,我几乎不会称之为问题。

但是如果你切换到DATAPAGESthen 你可能只锁定一行PAGE2k默认情况下),并且行驻留在一页中的进程将无法同时运行。

如果我们谈论的是同时锁定了几十行的表,那么几乎不会有任何明显的性能下降。

进程并发对于这样的设计更为重要。

于 2009-02-18T20:58:11.530 回答
1

最明显的方法是加锁,如果你的数据库没有加锁,你可以自己添加一个“Locked”字段来实现。

简化并发的一些方法是随机访问未处理的项目,因此它们不是在第一个项目上竞争,而是随机分配访问。

于 2009-02-19T05:33:32.290 回答
0

将该过程转换为单个 SQL 语句,并将多行作为单个批处理进行处理。这就是数据库应该如何工作的方式。

于 2009-02-19T04:59:18.347 回答