多线程从数据库优化中选择行

时间:2013-07-05 12:08:38

标签: java multithreading database-design data-binding

我有一个java应用程序,其中15个线程通过名为getNext()的同步方法从表中选择一行11,000条记录,线程在选择一行时变慢,从而花费了大量时间。每个线程都遵循以下过程:

  1. 线程检查是否存在恢复列值设置为1的行。

    一个。如果存在,则线程获取该行的id并使用该id选择id大于获取id的另一行。

    B中。否则,它选择id大于0的行。

  2. 根据上述1中描述的步骤结果收到的最后一行标记为恢复列设置为1.

  3. 线程获取行数据并对其进行处理。

  4. 问题:

    1. 多线程如何访问同一个表,选择另一个线程未选择并且速度快的行?
    2. 如果在任何线程选择的最后一行发生崩溃,线程如何恢复?

3 个答案:

答案 0 :(得分:1)

1 .: 似乎getNext()艺术中的多个数据库操作是瓶颈。如果数据没有被外部源更改,您可以读取所有行的“id”和“resume”并缓存它。比你只有一个查询而不是只在内存中进行读取操作。这将在getNext()中安全地进行大量昂贵的DB调用:

2 .: 基本上,您需要某种事务,或者至少添加一个在线程完成处理该行时更新的其他列。基本上,处理和更新需要在单个事务中发生。当事务未完成时发生某些事情时,您可以回滚到未处理该行的状态。

答案 1 :(得分:1)

如果线程都在同一台机器上,那么它们可以使用共享数据结构来避免处理相同的事情而不是同步。但以下假设线程在不同的机器上(可能是应用程序服务器集群的不同成员),并且只能通过数据库进行通信。

删除getNext()方法上的同步。将恢复标志设置为1(步骤2)时,请以原子方式执行此操作。 update table set resume = 1其中resume = 0,commit。只有一个线程会成功,这个线程确实得到了这个工作单元。同时,设置一个恢复时间 - 如果恢复时间大于某个最大值假设处理该工作单元的线程哈希崩溃,则将resume标志恢复为0.工作完成后,将恢复时间设置为null ,或以其他方式将工作标记为已完成。

答案 2 :(得分:1)

嗯,这里会想到不同的问题:

  1. 您是否在数据库中保留状态?我会寻找一种方法,你可以调用select for update,你可以按非活动状态过滤(确保只在select中获取一行)并立即更新为active(在同一个事务中)。很高兴知道你正在使用什么数据库,不确定“选择更新”是否总是一个选项。

  2. 处理完成后,请更新为已完成状态。

  3. 请务必在表格中保留时间戳,以便在最后一次更改状态时进行识别。让自己成为决定何时将活动线程视为丢失的规则。

  4. 定义其他可能的错误情况(如果进程失败会发生什么情况)。

  5. 您还需要分析方案。你的桌子有多少行?有多少线程同时调用它?在给定时间内发生了多少次插入?根据这一点,您将看到DB性能如何运行。

    我假设你的getNext()是同步的,我在第1点写的你可能会解决这个问题......