更新大表时出现错误1206

时间:2012-12-18 16:47:13

标签: mysql

我有一个存储过程,我在更改表时使用它并且失败了 错误消息:

  

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 answer建议锁定要写入的表。我试过了 使用'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;
...

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

提前感谢您的帮助

0 个答案:

没有答案