我正在使用nested sets将分层数据存储在MyISAM表中;该表由每个用户的几个分层集组成。每个用户将是唯一一个写入其各自树的用户,但其他用户可以从中读取。节点删除/插入要求同一树中的其他行的lft和rgt值更新,可能有数百行。
为了做到这一点,我需要获得一个表写锁,更新树中的其他节点,删除/插入行并解锁表。
我想知道的是 - 表锁定规模扩展到数百个并发用户吗?数千?
在这种情况下,InnoDB的行锁会更有效吗? (锁定几百行,主要仅由用户自己使用)
如果我要使用行锁,我是否需要添加显式逻辑来处理死锁错误?
答案 0 :(得分:5)
嗯,锁定的理念在两个引擎之间是不同的。
使用MyISAM,全表锁定的原因是写入通常应该很快。写入只需要两个操作(锁定表,然后将行写入磁盘)。由于这个原因,MyISAM性能实际上受磁盘速度的限制。
使用InnoDB,它会变得有点复杂。由于它完全符合ACID,因此每次写入需要4个步骤(锁定行,写入事务日志,将行写入dis,写入事务日志)。请注意,它会三次写入磁盘。这意味着(在实践中)InnoDB写入将比MyISAM写入花费3倍。这是行级别锁定的一个原因(事务是另一个)。
但这并不容易。使用MyISAM,表锁需要该表的一个信号量。因此,对内存使用和速度的影响充其量是微不足道的。但是,对于InnoDB,它需要一个索引和每行一个信号量。它需要一个索引来加速“检查”以查看是否已经锁定了该行。现在,如果你同时更新一行或10行,那就没什么区别了。但是当你谈论数百万行时,差异可能是非平凡的(在内存使用和速度上都是如此,因为它需要横向锁定每个要锁定的“索引”)。
还有一个额外的权衡。由于InnoDB符合ACID标准,如果出现断电(或其他崩溃),您永远不会处于不一致状态。数据库中没有未提交的事务数据,并且没有已提交的事务已损坏(如果它检测到要修复的事务,它将自动运行事务日志)。使用MyISAM,写入期间的断电(或崩溃)可能会使表处于不一致状态,并且您无法对其进行任何操作。如果你关心你的数据,InnoDB会更好。但是,有了良好的二进制日志和备份系统,你应该能够恢复MyISAM,但它需要一些人工干预......
现在,有了这个说,你的哪个尺度更好的问题真的很难。首先,你的大多数写作是处理一行还是两行?如果是这样,InnoDB和Row级锁定将更容易扩展。如果你做了很多同时更新大量行(数万及以上)的查询,你会发现MyISAM往往会有更好的性能。
至于你的死锁问题,MySQL将为你找到并处理它们(但它不会执行其中一个查询,所以你可能需要一些异常处理代码来重试查询或其他东西)。内部系统将防止僵局...
现在,另一个说明。由于MySQL支持db中的多个引擎,为什么不将数据放入InnoDB,然后创建一个MyISAM连接表来处理嵌套的set数据?将父母信息存储在数据表中(通过parent_id
机制)。这样,您的所有数据都在符合ACID标准的数据库中,但您可以通过使用更快(对于读取和大写入)MyISAM来嵌套集合逻辑来提高速度......