在大型MySQL表

时间:2016-03-02 21:02:10

标签: mysql innodb

我继承了一个有很多问题的数据库。我目前要解决的问题之一是,许多表都有字符主键,用10个字符填充空格。

在大多数情况下,我已经能够更新表格以轻松删除填充。但是,有一个辅助表,有超过一千万条记录。它有一个带有填充主键的表的外键。

我想将此外键列的所有值更新为其修剪值。我尝试了一个简单的更新查询。

UPDATE actions SET foreignkey = TRIM(foreignkey);

这给了我错误“锁的总数超过了锁表大小”。通过更改innodb_buffer_pool_size看起来可能有一个修复,但我决定尝试另一种策略。让我感到震惊的是,如果我重新创建表并选择它,我会避免这个错误,也不会因为搞乱索引字段而减速。

CREATE TABLE actions2 LIKE actions;
INSERT INTO actions2 (id, foreignkey, otherfields) SELECT id, TRIM(foreignkey), otherfields FROM actions;

如果我事先没有禁用表的索引,这个解决方案会比UPDATE解决方案快得多吗?有没有更快的方法来做到这一点,我错过了?

编辑:此表的外键和另一个表的主键是VARCHAR(10)字段。另外,我可以在一批中仅将最新的200万条记录加载到表中,并随着时间的推移慢慢填充其余记录。

1 个答案:

答案 0 :(得分:1)

我会以“块”的形式走过那张桌子,一次做1000行。这是一些伪代码。 (详细信息取决于您希望使用的语言。)

$a = '';  -- assuming this is less than any value
loop...
    $z = SELECT v FROM main
        WHERE v > $a  ORDER BY v  LIMIT 1000,1;  -- efficient locate stopper
    BEGIN;
    -- Update each table
    UPDATE main SET v = TRIM(v)
        WHERE v > $a AND v <= $z;
    UPDATE table2 SET v = TRIM(v)
        WHERE v > $a AND v <= $z;
    UPDATE table3 SET v = TRIM(v)
        WHERE v > $a AND v <= $z;
    COMMIT;   -- this keeps anyone from stumbling over FKs in transition
    if finished, exit loop
    $a = $z
end loop

More discussion

我有点随意选了1000。它可能足够小,对运行系统的影响最小,但又足够大,不能永远占用。

注意:如果您已经有一些修剪过的值,您是否可以前往“重复密钥”?