【问题标题】:Java Multithreaded delete on same sets of tableJava多线程删除同一组表
【发布时间】:2012-07-17 21:19:14
【问题描述】:

我必须清理数据库(几个表具有给定的条件,其中条件的列总是相同的)例如

delete from table1 where date < given_date1 and id = given_id
delete from table2 where date < given_date2 and id = given_id

其中 given_id 和 givendate 关系在逐个表和逐个 id 上各不相同。

实际的删除条件并不总是 where date

之前该脚本被编写为 sql 脚本并执行其操作但需要时间,现在我已经实现了一个多线程 Java 应用程序,其中新代码看起来像

for(i=0; i < idcount ; i++)
{
   //launch new thread and against that thread call
   delete(date,currentid);
}

function delete(date,id)
{
    delete from table1 where date < given_date and id = given_id
    delete from table2 where date < given_date and id = given_id

}

在实现这个之后我发现sql表死锁了,通过索引表解决了这个问题,但仍然没有想象中的那么快,如果我有500个线程,它们都是一个接一个地启动,并且显然在运行同组表。并且 sql 实际上并没有在每个表上并行执行?

当我监控我的 java.exe 和 sqlserver.exe 时,它​​一点也不忙?我希望它应该是。

谁能告诉我在同一组表上实现多线程删除的最佳方法是什么,以便我可以启动线程并并行执行删除并消耗可用资源

【问题讨论】:

  • 你说的“不如预期的快”是什么意思? java 和 sqlserver 进程可能都在等待 IO。
  • +1 到@vainolo。此外,您有一个磁盘设备。无论有多少线程在冲击您的 SQL 服务器,您都将受到磁盘 IO 的约束。 DELETE ... IN 是正确的解决方案。
  • 我的意思是当我运行 sql 脚本来清除表时,我有 4000 个 id,比如 20 个表,这 4000 个 id 和 20 个表在 7 小时内被清除(还有更多表 20 仅用于例如,但是是的,在 7 小时内完成),现在当多线程 java 程序运行时,我希望这会在一个小时或更早的时间内完成(因为它有 500 个线程),或者我期待错了吗? Sql server 事务日志已关闭。
  • 嗨 Gray,实际的删除条件并不总是 where date

标签: java sql-server multithreading sql-delete


【解决方案1】:

如果在给定的 id 上删除所有操作,我将只对每个表执行一次删除所有 id 的操作。

例如

delete from table1 where date < given_date and id in (given_id1, given_id2 ..... )

如果有很多 given_id,首先将它们插入到临时表中,然后通过将表连接到临时表中来执行每个删除操作

此外,如果尝试使用多个线程,那么只有当您在线程中对表进行操作时才能真正预期改进,这样就不会在数据库中发生争用。

【讨论】:

  • 感谢您的提示,当我更改架构以便一个线程进入一个表时,我变得更快,因此所有不同的表都被并行清除而不会发生争用。
【解决方案2】:

忽略您创建的问题...

为什么不使用IN 语句?

delete from table1 where date < given_date and id IN (id1, id2, id3, ...)

根据澄清更新: 根据 cmets 中的解释,我的猜测是您没有良好的索引,并且每个 delete 语句都会导致表扫描。每次表扫描都会锁定表,因此数据库一次只能处理一条语句。索引dateid 列以及delete 语句的where 子句中使用的任何其他列。

【讨论】:

  • 实际删除条件并不总是 where date
  • 感谢更新,但是所需列的索引已经完成,所以where子句中出现的所有列都已被索引,但是增加线程时性能仍然不好。
  • 不幸的是,这取决于您的期望与现实。在不真正了解您正在做的工作量的情况下,没有人可能评估所花费的时间是否合理。我的下一个最佳猜测是,大量删除查询存在显着重叠,导致一些锁争用。如果您使用的是 SQL Server,您可以尝试添加 NOLOCK 以查看 delete 语句在没有任何锁定的情况下运行的速度。
  • 嗨蒂姆,我相信锁争用也是如此,但只是指出 NOLOCK 不可用于删除、更新、插入,因为 nolock 和 readuncommitted 仅允许用于读取数据库。
【解决方案3】:

根据我的个人经验,我开设了一个课程来管理我的查询以及与数据库的通信。我使用线程池来管理我的线程,并简单地让线程调用我的静态数据库管理器。管理器中应该有一个同步方法,该方法在数据库连接上获取lock()。然后线程将能够访问数据库,并且它们的操作不会相互冲突。

【讨论】:

  • 我已经使用线程池和连接池实现了我的代码,其中 500 是构建池的初始线程数,连接池也是如此,我同意表在执行删除查询和锁定时间之前获取锁定通过索引表已经减少了,但我个人认为它没有像它应该做的那样使用 500 个线程。
【解决方案4】:

如果您不关心在一个事务单元中生成所有命令,那么将删除放在它自己的事务中(小事务)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多