MySQL删除行的死锁

时间:2009-08-20 15:18:32

标签: mysql deadlock innodb

我们有一个(目前是InnoDB)表,其中包含大约500,000行。这表示要运行的任务队列。它存储在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,这可能就足够了。

2 个答案:

答案 0 :(得分: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;

在这种情况下,MySQL选择RANGE上的id访问路径,它认为REF上的data便宜{/ 1}}。

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

如果您从上述条件中删除id <= 5,则可以删除行3中的任何行。

很遗憾,您无法控制MySQL操作中的DML访问路径。

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

答案 1 :(得分:2)

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

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

SHOW VARIABLES LIKE 'tx%';

要设置此项,请在my.cnf文件中输入以下行:

tx_isolation=READ-COMMITTED