我有一个在表更改期间使用的存储过程,它失败并显示错误消息:
ERROR 1206 (HY000): 锁总数超过锁表大小
我在网上四处寻找,在这里和 mysql 论坛上找到了条目,共识似乎是增加 innodb_buffer_pool_size 的大小或减少在单个操作中添加/更改的记录数量。
可悲的是,我没有增加 innodb_buffer_pool_size 的选项或能力,所以我试图减少每个操作更改的记录数。然而,这也失败了。
我们有一个简单的时间分区表 event_notify_occurrence_cache,它有两列:
CREATE TABLE `event_notify_occurrence_cache` (
`timestamp` datetime NOT NULL,
`xml` text NOT NULL,
KEY `idx_timestamp` (`timestamp`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8
/*!50500 PARTITION BY RANGE COLUMNS(`timestamp`)
(PARTITION p2012_12_10__15_00_00UTC VALUES LESS THAN ('2012-12-10 16:00:00') ENGINE = InnoDB,
PARTITION p2012_12_10__16_00_00UTC VALUES LESS THAN ('2012-12-10 17:00:00') ENGINE = InnoDB,
...
...
...
我们需要将其更改为具有“事件类型”列,其中事件类型是 xml 列中字符串的一部分。执行“LIKE”搜索明显很慢,因此我们想为事件类型添加另一个索引列。我们要更改为以下内容:
CREATE TABLE `event_notify_occurrence_cache` (
`event_type_value` smallint(5) unsigned NOT NULL,
`timestamp` datetime NOT NULL,
`xml` text NOT NULL,
KEY `idx_timestamp` (`timestamp`),
KEY `idx_event_type_value` (`event_type_value`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
/*!50500 PARTITION BY RANGE COLUMNS(`timestamp`)
(PARTITION p2012_12_10__15_00_00UTC VALUES LESS THAN ('2012-12-10 16:00:00') ENGINE = InnoDB,
PARTITION p2012_12_10__16_00_00UTC VALUES LESS THAN ('2012-12-10 17:00:00') ENGINE = InnoDB,
...
...
当我们更改表以匹配它时,event_type_value 列会按照预期和期望填充无效事件类型零(0)。
到目前为止,这一切都有效。
因此,下一步是使用基本上等同于以下的逻辑,对每种可能的事件类型在表上进行一系列更新:
UPDATE event_notify_occurrence_cache
SET event_type_value = 1
WHERE event_type_value = 0 AND xml LIKE "%<eventType>1</eventType>";
对每种可能的事件类型重复此操作。
这对于我们的一个测试用例来说失败了,我们有 24 个分区,总共 9,110,000 条记录,其中第一次匹配将达到大约 201,827 条记录。
我尝试使用LIMIT
带有UPDATE
子句的语句并循环,直到给定事件类型的所有条目都完成,但这不起作用。
我首先尝试限制为 5000,但在 150,000 条记录后失败(根据调试输出)。接下来,我将限制设置为 1000,现在它在 152,000 条记录后失败。在随后的尝试中,我将该UPDATE
子句包装在一个TRANSACTION
/COMMIT
对中,那次我在它出错之前将其记录到了 182,000 条记录。
这几乎就像锁表是每个存储过程而不是每个语句。
一个stackoverflow 答案建议锁定正在写入的表。我尝试使用“LOCK TABLE”命令,但它仍然不起作用。
我正在使用服务器版本 5.5.8-enterprise-commercial-advanced-log
我的存储过程逻辑尝试之一的示例如下
....
OPEN etype;
REPEAT
FETCH etype INTO etype_name, etype_value;
IF done != 1 THEN
SET query_str :=
CONCAT('%<eventType>', etype_name, '</eventType>%');
SET changes_not_done := 1;
WHILE changes_not_done != 0 DO
SELECT CONCAT(CURRENT_TIMESTAMP(), ' ETYPE:', etype_name,
' CHANGES_NOT_DONE:', changes_not_done)
AS 'Debug Msg:';
UPDATE `UMS`.`event_notify_occurrence_cache`
SET event_type_value=etype_value
WHERE event_type_value=0 AND xml LIKE query_str
LIMIT 1000;
-- set changes_not_done to the number of rows modified by the
-- previous command. If it's zero, then we are done. If it's
-- non-zero then we have more to do.
SELECT ROW_COUNT() INTO changes_not_done;
END WHILE;
END IF;
UNTIL done = 1
END REPEAT;
CLOSE etype;
...
我有一个事件类型表,我循环遍历它,并为每个事件类型搜索通知缓存以处理它。
在此先感谢您的帮助