2009-08-20 43 views
9

我们有一个(目前InnoDB)表,其中包含大约500,000行。这表示要运行的任务队列。它存储在一个MySQL数据库中。MySQL删除行上的死锁

一个持续的基础,至少每秒一次,但有时更频繁,我们从中选择数据并随后更新一些行。我们每天一次修剪表格中的旧行。

我们开始在桌上发现死锁,这导致我们的任务处理陷入停滞。这些僵局是在夜间修剪过程中造成的。 DELETE,SELECT和UPDATE的组合意味着基本上没有什么生产力可能发生。我不幸没有SHOW ENGINE INNODB STATUS的输出。

我想知道处理这个问题的最佳选择。请注意,我们的代码检测到死锁并重新发出查询。另外,我们很久以前发现,一次删除所有匹配的行对于看到很多活动的数据库表太重要了,因此我们一次将删除限制为10,000行,并继续重新发出查询,直到所有必需的行都被修剪。

我看到下面的选项,并愿意见上是最好的,或者其他的选择建议:

  1. 同时
  2. 使用我们的DELETE指数退避删除的行数少,但我我担心这不会有助于我们的具体工作量
  3. 按照MySQL documentation锁定表。我们可以接受在删除期间阻止SELECT和UPDATE语句。
  4. 切换到MyISAM表类型。我们使用InnoDB,因为我们最初是在这张桌子上使用交易。这已不再是这种情况。我不太了解具体情况,以了解这是否是一种可行的解决方案。
  5. 也许使用UPDATE LOW_PRIORITY。可能是DELETE不会影响SELECT,只有UPDATE,这可能就足够了。
+1

我遇到的所有死锁都是由于未提交的事务。确保您正确地运行事务(或者使用自动提交或自动提交关闭并实际处理提交/回滚)。 – localshred 2009-08-20 15:23:04

+0

绝对是一个好点;大多数情况下都是这种情况,但我们实际上并未在此表上进行交易。我们曾经,但不再做。 – ChrisInEdmonton 2009-08-20 15:32:14

回答

4

在进行DML操作,InnoDB锁扫描的所有行都不匹配。

考虑这个表格布局:

DROP TABLE t_tran; 

CREATE TABLE t_tran (id INT NOT NULL PRIMARY KEY, data INT NOT NULL, KEY ix_tran_data (data)) Engine=InnoDB; 

DROP TABLE t_tran; 

CREATE TABLE t_tran (id INT NOT NULL PRIMARY KEY, data INT NOT NULL, KEY ix_tran_data (data)) Engine=InnoDB; 

INSERT 
INTO t_tran 
VALUES 
(1, 1), 
(2, 2), 
(3, 3), 
(4, 4), 
(5, 5), 
(6, 6), 
(7, 7), 
(8, 8); 

START TRANSACTION; 

DELETE 
FROM t_tran 
WHERE data = 2 
     AND id <= 5; 

在这种情况下,选择MySQLidRANGE访问路径,它认为价格比REFdata

在并发交易,您将能够删除或更新行678但不排15,因为它们被锁定(尽管只排2受到影响)。

如果您从上述条件中删除id <= 5,您将能够删除行,但行3

不幸的是,您无法控制DML操作中的MySQL访问路径。

你可以做的最好的事情是正确地索引你的条件,并希望MySQL会选择这些索引。

+0

谢谢,我们(我的系统管理员和我)认为这实际上可能是最好的解决方案。我们还减少了删除量并增加了指数回退。我们会看看是否照顾到这个问题。 – ChrisInEdmonton 2009-08-20 16:23:58

1

请确保您的事务隔离被标记为已读提交且不可重复读取。读取提交应该是默认的,但我们看到在我们的服务器中innodb默认是可重复读取的。

您可以通过运行检查以下内容:

SHOW VARIABLES LIKE 'tx%'; 

为了设置这一点,在你的my.cnf文件进入folloiwing行:

tx_isolation=READ-COMMITTED