ola*_*ndo 10 mysql deadlock innodb
我有以下查询(所有表都是innoDB)
INSERT INTO busy_machines(machine)
SELECT machine FROM all_machines
WHERE machine NOT IN (SELECT machine FROM busy_machines)
and machine_name!='Main'
LIMIT 1
Run Code Online (Sandbox Code Playgroud)
当我在线程中运行时会导致死锁,显然是因为内部选择,对吧?
我得到的错误是:
(1213, 'Deadlock found when trying to get lock; try restarting transaction')
Run Code Online (Sandbox Code Playgroud)
我怎样才能避免死锁?有没有办法改变查询以使其工作,或者我是否需要做其他事情?
当然,只有在多次运行此查询并且在多个线程中之后,才会始终发生错误.
ewe*_*nli 12
根据我的理解,select不会获得锁定,也不应该成为死锁的原因.
每次插入/更新/删除行时,都会获取锁定.为避免死锁,您必须确保并发事务不会按顺序更新行,从而导致死锁.一般来说,为了避免死锁,即使在不同的事务中,也必须始终以相同的顺序获取锁(例如,总是先用表A,然后再用表B).
但是,如果在一个事务中只插入一个表,则满足此条件,这通常不会导致死锁.你在交易中做了别的事吗?
但是,如果缺少索引,则会发生死锁.当插入/更新/删除行时,数据库需要检查关系约束,即确保关系一致.为此,数据库需要检查相关表中的外键.它可能导致获取其他锁定而不是被修改的行.确保始终在外键(当然还有主键)上有索引,否则可能导致表锁而不是行锁.如果发生表锁定,则锁争用会更高,并且死锁的可能性会增加.
不确定在你的情况下究竟发生了什么,但也许它会有所帮助.
如果用外连接替换"NOT IN",您可能会获得更好的性能.
您还可以将其分为两个查询,以避免在单个查询中插入和选择相同的表.
像这样的东西:
SELECT a.machine
into @machine
FROM all_machines a
LEFT OUTER JOIN busy_machines b on b.machine = a.machine
WHERE a.machine_name!='Main'
and b.machine IS NULL
LIMIT 1;
INSERT INTO busy_machines(machine)
VALUES (@machine);
Run Code Online (Sandbox Code Playgroud)