10

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

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

我们开始在桌面上遇到死锁,这使我们的任务处理陷入停顿。这些死锁是在夜间修剪运行期间造成的。DELETE、SELECT 和 UPDATE 的组合意味着基本上不会发生任何有成效的事情。不幸的是,我没有 SHOW ENGINE INNODB STATUS 的输出。

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

我看到以下选项,并想就哪些是最佳选项提出意见,或对其他选项提出建议:

  1. 一次删除更少的行
  2. 在我们的 DELETE 上使用指数退避,尽管我担心这对我们的特定工作量没有帮助
  3. 根据MySQL 文档锁定表。我们可能会接受在删除期间阻塞 SELECT 和 UPDATE 语句。
  4. 切换到 MyISAM 表类型。我们选择 InnoDB 是因为我们最初在此表上使用事务。这已不再是这种情况。我对细节不够熟悉,不知道这是否是一个可行的解决方案。
  5. 也许使用 UPDATE LOW_PRIORITY。可能是 DELETE 不会影响 SELECT,只会影响 UPDATE,这可能就足够了。
4

2 回答 2

6

执行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访问路径 on id,它认为它比REFon便宜data

在并发事务中,您将能够删除或更新行6,但不能更新行7,因为它们被锁定(尽管只有行受到影响)。8152

如果您id <= 5从上述条件中删除,您将能够删除除 row 之外的任何行3

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

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

于 2009-08-20T15:57:08.347 回答
2

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

您可以通过运行以下命令进行检查:

SHOW VARIABLES LIKE 'tx%';

为了设置它,在您的 my.cnf 文件中输入以下行:

tx_isolation=READ-COMMITTED
于 2009-08-20T15:41:32.810 回答