以下是三个字段中的一些mysql inno_bd表t
主键id
和多个 btree 索引。
字段A,B,C分别为int
,int
,Date
:
问题在于:
我有一个归档t_archive
表,用于将记录从t
移动到t_archive
(如果已经过时)。要移动记录,我使用两个查询:
INSERT INTO t_archive SELECT * FROM t WHERE A = 1 AND B = 2 AND C = 3
DELETE FROM t WHERE A = 1 AND B = 2 AND C = 3
(正如您所注意到的,满足条件ID为4和5)
在上述查询期间,我尝试UPDATE
使用ID进行重新计算:1和8。
从逻辑上讲,没有理由lock
记录1,2,3,6,7,8个任何类型的查询,
但它发生了!
由于真正的红色扇区比例子大得多,转移操作需要花费很多时间(大约50秒),我无法使用其他recs(只是UPDATE,其中id = 8) - 获得异常:Lock wait timeout exceeded; try restarting transaction
< / p>
有人可以解释为什么会发生这种情况以及如何避免它吗?
答案 0 :(得分:0)
如果使用更棘手的DELETE
查询,问题就会消失:
DELETE t FROM my_table t,
(SELECT t1.id AS del_id FROM my_table t1
WHERE t1.A=1
AND t1.B=2
AND t1.C=3) AS del
WHERE t.id=del.del_id;
答案 1 :(得分:0)
如果这是一个“大”表,如果你没有合适的索引,例如INDEX(a,b,c)
(按任意顺序),则DELETE
需要很长时间才能扫描表格,挂起锁定它获取它们。这存在锁定等待超时或甚至死锁的风险。
如果表格“小”和/或您有一个好的索引,是否会发生超时?
回到为什么DELETE
带有子查询以使ids
可能侵入性较小的问题:
首先使用最小锁运行SELECT
子查询。然后运行DELETE
,至少需要对所讨论的2行进行排他锁定。如果它没有超时,我怀疑这是因为在这个“两步”版本中获取锁的时间。