我有一个超过160百万条目的表,它有一个错误的表引擎,所以我要改变引擎。 当我这样做而没有任何准备时,由于我的缓冲区大小,我得到一个错误,因为行锁太多
mysql> ALTER TABLE foobar ENGINE=MyISAM;
ERROR 1206 (HY000): The total number of locks exceeds the lock table size
我现在想要在此操作之前锁定整个表,然后解锁整个表。
mysql> LOCK TABLES foobar WRITE;
我的问题:mysql服务器是否注意到表锁已经处于活动状态并跳过行锁或让它锁定表,现在还会再次锁定每一行,我会再次遇到同样的错误?
我也对任何其他游戏开放如何以最快的方式改变这么大(和更大)的桌子的引擎:)
答案 0 :(得分:3)
您可以进行实验:
在第一次运行中:
mysql> LOCK TABLE foobar WRITE;
mysql> ALTER TABLE foobar ENGINE=MyISAM;
在第二个会话中(即打开第二个终端窗口),运行:
mysql> SHOW ENGINE INNODB STATUS\G
在TRANSACTIONS部分中,您将找到正在进行的ALTER线程:
---TRANSACTION 69638, ACTIVE 45 sec fetching rows
mysql tables in use 1, locked 1
14626 lock struct(s), heap size 1898936, 5145657 row lock(s)
哇!尽管LOCK TABLE生效,它仍会创建许多单独的行锁。
(这只是一个例子;当ALTER TABLE在你的表中工作时,你会看到行锁的数量随着时间的推移而增加。)
因此,您需要为大量行锁保证空间。
https://dev.mysql.com/doc/refman/5.6/en/innodb-error-codes.html说:
1206(ER_LOCK_TABLE_FULL)
锁的总数超过了InnoDB用于管理锁的内存量。为了避免此错误,增加
innodb_buffer_pool_size
的值。在单个应用程序中,解决方法可能是将大型操作分解为更小的部分。例如,如果大INSERT
发生错误,请执行几个较小的INSERT
操作。
(强调我的)
另请阅读How much memory Innodb locks really take?
Innodb行级锁通过具有特殊锁定表来实现,该锁定表位于缓冲池中,其中可以设置为每个散列分配的小记录以及锁定在该页面位上的每一行。理论上,这可以使每行的开销低至几位。
锁定1.6亿行需要锁表中大约60-80MB的空间。您的缓冲池可能太小而无法容纳它。
在MySQL 5.1.27及更早版本中,InnoDB缓冲池的默认大小仅为8MB。在MySQL 5.1.28中,默认值增加到128MB。
重新评论:
每个工具都可以完成它的工作;) - MyISAM也是如此
MyISAM不支持原子性,一致性,隔离性或持久性。除此之外,它很棒。 : - )
答案 1 :(得分:1)
通常,如果您的InnoDB缓冲池不足以容纳表中所有行的行锁(有时是必要的话),则会增加InnoDB缓冲池大小(innodb_buffer_pool_size)。
尝试将innodb_buffer_pool_size增加到128 MB。
如果您仍然遇到问题,可以尝试创建新的MyISAM表,然后执行INSERT INTO ... SELECT FROM ...
将数据从InnoDB表复制到MyISAM表。您可以以块的形式复制行以减少行锁。