1

我有一个在表更改期间使用的存储过程,它失败并显示错误消息:

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;
...

我有一个事件类型表,我循环遍历它,并为每个事件类型搜索通知缓存以处理它。

在此先感谢您的帮助

4

0 回答 0