MySQL在大表中添加列的性能

时间:2014-07-09 17:44:50

标签: mysql performance database-performance ddl

我在本地安装了InnoDB的MySQL 5.5.37和Ubuntu 13.10上的apt-get。我的机器是台式机上的i7-3770 + 32Gb内存+ SSD硬盘。对于只包含150万条记录的“mytable”表,以下DDL查询需要超过20分钟(!):

ALTER TABLE mytable ADD some_column CHAR(1) NOT NULL DEFAULT 'N';

有没有办法改善它? 我查了一下

show processlist;

并且它显示出由于某种原因它正在复制我的表。 令人不安的是令人不安的。有没有办法关掉这个副本? 是否有其他方法可以提高将列添加到大型表的性能?

除此之外,我的数据库相对较小,只有1.3Gb转储大小。因此它(理论上)应该100%适合记忆。

是否有可以提供帮助的设置? 迁移到Precona会改变我的一切吗?

添加:我有

innodb_buffer_pool_size = 134217728

5 个答案:

答案 0 :(得分:13)

  

是否有其他方法可以提高将列添加到大型表的性能?

简答:不。您可以立即添加ENUM和SET值,并且可以在仅锁定写入时添加二级索引,但是更改表结构始终需要表副本。

答案很长:你真正的问题不是真正的表现,而是锁定时间。如果它很慢并不重要,只有在ALTER TABLE完成之后其他客户端才能执行查询。在这种情况下有一些选择:

  1. 您可以使用Percona工具包中的pt-online-schema-change。先备份您的数据!这是最简单的解决方案,但可能无法在所有情况下都有效。

  2. 如果您不使用外键并且因为您有很多索引而速度很慢,那么使用您需要的更改来创建表的副本可能会更快,但是没有二级索引,请填充它使用数据,并在末尾使用单个alter table创建所有索引。

  3. 如果你很容易创建副本,就像你在Amazon RDS上托管一样,你可以创建一个主 - 主副本,在那里运行alter table,让它恢复同步,并切换实例完成后。

  4. <强>更新

    正如其他人提到的,MySQL 8.0 INNODB增加了对即时列添加的支持。它不是一个神奇的解决方案,它有局限性和副作用 - 它只能是最后一列,表格不能有全文索引等 - 但在许多情况下应该有所帮助。

    您可以指定显式ALGORITHM=INSTANT LOCK=NONE参数,如果无法立即更改模式,MySQL将失败并返回错误,而不是回退到INPLACECOPY。例如:

    ALTER TABLE mytable
    ADD COLUMN mycolumn varchar(36) DEFAULT NULL,
    ALGORITHM=INPLACE, LOCK=NONE;
    

    https://mysqlserverteam.com/mysql-8-0-innodb-now-supports-instant-add-column/

答案 1 :(得分:4)

MariaDb 10.3,MySQL 8.0以及可能跟随的其他MySQL变体都有一个&#34; Instant ADD COLUMN&#34;功能,大多数列(有一些约束,请参阅文档)可以立即添加,没有表重建。

答案 2 :(得分:2)

答案 3 :(得分:1)

由于结构发生变化,因此无法在添加或删除列时避免复制表。您可以在没有表副本的情况下添加或删除辅助索引。

您的表格数据不会驻留在内存中。索引可以驻留在内存中。

150万条记录不是很多行,20分钟看起来很长,但也许你的行很大而且你有很多索引。

在复制表格时,您仍然可以从表格中选择行。但是,如果您尝试进行任何更新,它们将被阻止,直到ALTER完成。

答案 4 :(得分:0)

我知道这是一个比较老的问题,但是今天我遇到了类似的问题。我决定创建一个新表并将旧表导入新表中。像这样:

CREATE TABLE New_mytable  LIKE mytable ;

ALTER TABLE New_mytable  ADD some_column CHAR(1) NOT NULL DEFAULT 'N';

insert into New_mytable  select * from mytable ;

然后

START TRANSACTION;
insert into New_mytable  select * from mytable where id > (Select max(id) from New_mytable) ;

RENAME TABLE mytable TO Old_mytable;

RENAME TABLE New_mytable TO mytable;
COMMIT;

这不会使更新过程进行得更快,但是可以最大程度地减少停机时间。

希望这会有所帮助。