[英]How to prevent MySQL InnoDB setting a lock for delete statement through JDBC
我有一个多线程的客户机/服务器系统,其中有成千上万的客户机不断向存储在特定表中的服务器发送数据。 这些数据仅在几天之内很重要,因此之后将被删除。
服务器是用J2SE编写的,数据库是MySQL,我的表使用InnoDB引擎。 它包含数百万个条目(并且已针对使用情况进行了正确索引)。
一个计划的线程每天运行一次,以删除旧条目。 由于删除的行数可能非常大(几百万行),因此删除该线程可能要花费大量时间。 在我的特定系统上,删除250万行大约需要3分钟。
插入线程(和读取线程)收到超时错误,告诉我
超过了锁定等待超时; 尝试重新启动事务
我可以用吗
conn.setIsolationLevel( Connection.TRANSACTION_READ_UNCOMMITTED )
用于读取线程,因此无论当前是否最准确,它们都将获取其信息(在此用例中绝对可以)?
在阅读MySQL文档时 ,我想知道是否不能简单地使用以下命令定义用于插入和删除行的连接
conn.setIsolationLevel( Connection.TRANSACTION_READ_COMMITTED )
并实现我所需要的。 它说,使用具有唯一搜索模式的唯一索引的UPDATE-和DELETE语句仅锁定匹配的索引条目, 但不锁定该间隙,并且在此之前 ,行仍可以插入该间隙。 最好能获得您的经验,因为我不能简单地在生产中试用它-在测试环境中进行仿真是一项巨大的努力。
尝试在您的删除线程中首先加载要删除的记录的ID,然后一次删除一个,在每次删除后提交。
如果您运行的线程每天执行一次大型删除,并且需要3分钟,则可以将其拆分为较小的事务,这些事务删除少量记录,并且仍然设法使其完成得足够快。
更好的解决方案:
首先。 您尝试的任何解决方案都必须在生产环境中部署之前经过测试。 特别是一些随机人在某个随机网站上建议的解决方案。
现在,这是我建议的解决方案(对表结构和索引进行一些假设,因为您没有指定它们):
更改您的表。 不建议在InnoDB中使用多列的主键,尤其是在大型表中(因为主键会自动包含在任何其他索引中)。 有关更多原因,请参见此问题的答案。 您应该添加一些唯一的RecordID列作为主键(我建议使用长标识符或MySQL中的BIGINT)。
选择要删除的行-执行“从YourTable选择SELECT RecordID,其中ServerTimeMillis <?”。
提交(以快速释放ServerTimeMillis索引的锁定,我认为您已经拥有该锁定)
对于每个RecordID,执行“从YourTable WHERE RecordID =?中删除”。
在每个记录之后或在每个X记录之后提交(我不确定这是否会有很大的不同)。 也许甚至在DELETE命令末尾的一个Commit也足够了,因为使用我建议的新逻辑,只有已删除的行才应被锁定。
至于更改隔离级别。 我认为您不必这样做。 我不建议您是否可以这样做,因为我不知道服务器的逻辑以及这种更改将如何影响它。
您可以尝试用多个较短的DELETE ... LIMIT n
替换您的一个巨大DELETE
,在测试后确定n
(不能太小而导致许多查询,也不能太大而导致长锁定)。 由于锁定将持续几毫秒(或几秒钟,具体取决于您的n
),因此您可以让删除线程连续运行(前提是它可以保持运行状态;再次可以调整n
使其保持运行状态)。 此外, 表分区也可以提供帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.