2010-05-13 87 views
2

关于在innodb中锁定的典型文档太混乱了。我认为这将是很有价值的有一个“傻瓜引导的InnoDB锁定”傻瓜指导在innodb中锁定

我会开始,我会收集所有的响应作为维基:

  • 列需要行之前被编入索引级别锁定适用。
    • 示例:delete row where column1 = 10;

      所有行和索引条目:除非COLUMN1被索引

回答

2

这里是我的笔记与MySQL支持在最近的一个,奇怪的锁定问题工作(5.1.37版本)将锁定表遍历到要更改的行将被锁定。它覆盖在:

http://dev.mysql.com/doc/refman/5.1/en/innodb-locks-set.html

“锁定读,一个UPDATE或DELETE上是在SQL语句的处理扫描的每个索引记录一般设置记录锁不要紧,是否有。 WHERE条件在语句中将排除该行InnoDB不记得确切的WHERE条件,但只知道扫描了哪些索引范围...如果没有适合您的语句的索引,并且MySQL必须扫描整个表以处理声明中,表的每一行都被锁定,这反过来阻止了其他用户对该表的所有插入。“

这是一个主要的头痛,如果属实的话。

它是。一个常用的解决方法是:

UPDATE whichevertable设置任何东西,其中primarykey在(从可转换的主键中按primarykey约束的顺序);

内部选择不需要进行锁定,因此更新将更少地进行更新。 order by子句确保更新是以主键顺序完成的,以匹配InnoDB的物理顺序,这是实现它的最快方法。

在涉及大量行的情况下(如您的情况),最好将选择结果存储在添加了标志列的临时表中。然后从没有设置标志的临时表中选择每个批次。运行限制为1000或10000的更新,并在更新后设置批处理标志。限制将锁定的数量保持在可接受的水平,而选择工作只需要进行一次。在每批之后提交以释放锁。

您还可以在进行每批更新之前,通过执行未索引列的选择总和来加速此工作。这会将数据页面加载到缓冲池中而不锁定。然后锁定将持续更短的时间,因为不会有任何磁盘读取。

这并不总是实际可行,但当它可能会非常有帮助。如果你不能批量执行,你可以至少尝试选择预先加载数据,如果它足够小以适应缓冲池。

如果可能,请使用READ COMMITTED事务隔离模式。请参阅:

http://dev.mysql.com/doc/refman/5.1/en/set-transaction.html

要获得减少锁定需要使用基于行的二进制日志(而不是基于二进制日志的默认语句)的。

两个已知问题:

  1. 子查询可以小于有时理想的优化。在这种情况下,这是一个不合乎要求的依赖子查询 - 与此案例中的替代方法相比,我提出的使用子查询的建议结果是无益的。

  2. 删除和更新没有与select语句相同的查询计划范围,所以有时很难在不测量结果的情况下正确优化它们以准确计算出他们正在执行的操作。

这两个都在逐渐改善。此错误是一个例子,我们刚刚提高可更新的优化方案,虽然变化是显著它仍然要通过QA,以确保它不会有什么太大的不良影响:

http://bugs.mysql.com/bug.php?id=36569