关于在innodb中锁定的典型文档太令人困惑了。我认为拥有“innodb锁定的假人指南”非常有价值。
我将开始,我将收集所有回复作为维基:
答案 0 :(得分:2)
以下是我在最近一个奇怪的锁定问题(版本5.1.37)上使用MySQL支持的注意事项:
将遍历所有要访问要更改的行的行和索引条目。它包括在:
http://dev.mysql.com/doc/refman/5.1/en/innodb-locks-set.html
“锁定读取,UPDATE或DELETE通常会在处理SQL语句时扫描的每个索引记录上设置记录锁定。语句中是否存在排除行的WHERE条件无关紧要InnoDB不记得确切的WHERE条件,但只知道扫描了哪些索引范围。...如果你没有适合你的语句的索引,MySQL必须扫描整个表来处理语句,表的每一行都会被锁定,这反过来阻止其他用户对表的所有插入。“
如果这是真的,这是一个严重的问题。
是的。通常有用的解决方法是:
更新无法设置的内容,无论是哪个主键都在哪里(从主键中选择主键从哪个约束顺序);
内部选择不需要锁定,因此更新将更少地进行更新。 order by子句确保更新以主键顺序完成,以匹配InnoDB的物理顺序,这是最快的方法。
如果涉及大量行,如您的情况,最好将选择结果存储在添加了标志列的临时表中。然后从未设置标志的临时表中选择以获取每个批次。运行限制为1000或10000的更新,并在更新后设置批处理的标志。限制将使锁定量保持在可容忍的水平,而选择工作只需要完成一次。在每批之后提交以释放锁。
您还可以在执行每批更新之前,通过选择未编制索引的列的总和来加快此工作。这会将数据页加载到缓冲池中而不需要锁定。然后锁定将持续更短的时间跨度,因为不会有任何磁盘读取。
这并不总是实用,但是当它变得非常有用时。如果您不能批量执行此操作,则至少可以先尝试选择预先加载数据,如果它足够小以适应缓冲池。
如果可能,请使用READ COMMITTED事务隔离模式。参见:
http://dev.mysql.com/doc/refman/5.1/en/set-transaction.html
要减少锁定,需要使用基于行的二进制日志记录(而不是基于默认语句的二进制日志记录)。
两个已知问题:
子查询有时可能不是理想的优化。在这种情况下,它是一个不受欢迎的依赖子查询 - 由于这个原因,我在使用子查询时提出的建议与此案例中的替代方案相比没有任何帮助。
删除和更新与select语句没有相同的查询计划范围,因此有时很难在不测量结果的情况下正确优化它们,以确切了解它们正在做什么。
这两项都在逐步改善。这个错误就是我们刚刚改进了可用于更新的优化的一个例子,尽管这些变化非常重要,并且它仍然通过质量保证来确保它没有任何重大的不利影响: