【发布时间】:2019-03-15 21:02:58
【问题描述】:
在 MySQL 中,我有两个 innodb 表,一个小型任务关键表,需要随时可供读取/写入。将此称为关键任务。我有一个更大的表(> 数百万行),称为 big_table。我需要更新 big_table,例如:
update mission_critical c, big_table b
set
b.something = c.something_else
where b.refID=c.id
此查询可能需要一个多小时,但这会在mission_critical 表上创建一个写锁。有没有办法告诉 mysql,“我不想锁定 Mission_critical”,以便可以写入该表?
我知道从交易的角度来看这并不理想。我现在能想到的唯一解决方法是制作一个小型任务关键表的副本并从中进行更新(我不在乎被锁定),但如果有办法制作,我宁愿不这样做MySQL 本身可以更优雅地处理这个问题。
锁定的不是表,而是mission_critical 中的所有记录,因为它们基本上都被更新扫描了。我不是假设这一点;症状是当用户登录到在线系统时,它会尝试更新 Mission_critical 中的 datetime 列以更新他们上次登录的时间。在上面的查询运行时,这些查询由于 Lock wait timeout exceeded 错误而死亡。如果我终止上面的查询,所有待处理的查询都会立即运行。
mission_critical.id 和 big_table.refID 都已编入索引。
每个表的创建语句的相关部分是:
关键任务:
CREATE TABLE `mission_critical` (
`intID` int(11) NOT NULL AUTO_INCREMENT,
`id` smallint(6) DEFAULT NULL,
`something_else` varchar(50) NOT NULL,
`lastLoginDate` datetime DEFAULT NULL,
PRIMARY KEY (`intID`),
UNIQUE KEY `id` (`id`),
UNIQUE KEY `something_else` (`something_else`),
) ENGINE=InnoDB AUTO_INCREMENT=1432 DEFAULT CHARSET=latin1
大表:
CREATE TABLE `big_table` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`postDate` date DEFAULT NULL,
`postTime` int(11) DEFAULT NULL,
`refID` smallint(6) DEFAULT NULL,
`something` varchar(50) NOT NULL,
`change` decimal(20,2) NOT NULL
PRIMARY KEY (`id`),
KEY `refID` (`refID`),
KEY `postDate` (`postDate`),
) ENGINE=InnoDB AUTO_INCREMENT=138139125 DEFAULT CHARSET=latin1
查询的解释是:
+----+-------------+------------------+------------+------+---------------+-------+---------+------------------------------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------------+------------+------+---------------+-------+---------+------------------------------------+------+----------+-------------+
| 1 | SIMPLE | mission_critical | | ALL | id | | | | 774 | 100 | Using where |
| 1 | UPDATE | big_table | | ref | refID | refID | 3 | db.mission_critical.something_else | 7475 | 100 | |
+----+-------------+------------------+------------+------+---------------+-------+---------+------------------------------------+------+----------+-------------+
【问题讨论】:
-
InnoDB 不锁定表,InnoDB 锁定记录,它可能会锁定一个 foreiyn 键,另外你不应该使用旧的逗号 ansi join annymore .. 如果你的 MySQL 版本支持它使用@987654325 @ 还提供两个表的表结构
SHOW CREATE TABLE table -
“小”表有多大?
-
@Paul,小桌子大概有1000行。
-
你有
b.refID的索引吗?您是否运行了一个测试,告诉您该表已锁定以进行更新,或者您是否在做出假设? -
@RaymondNijland 我在问题的编辑版本中添加了额外的细节。