ALTER TABLE ADD COLUMN需要很长时间

时间:2011-09-29 15:16:17

标签: mysql performance alter

我只是想在数据库中的表(main_table)中添加一个名为“location”的列。我运行的命令是

ALTER TABLE main_table ADD COLUMN location varchar (256);

main_table包含> 2,000,000行。它持续运行超过2小时仍未完成。

我尝试使用mytop 监视此数据库的活动,以确保查询未被其他查询过程锁定,但似乎没有。应该花那么长时间吗?实际上,我刚刚在运行此命令之前重启了机器。现在这个命令仍在运行。我不知道该怎么做。

5 个答案:

答案 0 :(得分:166)

你的ALTER TABLE语句暗示mysql必须重写表的每一行,包括新列。由于您有超过200万行,我肯定会花费大量时间,在此期间您的服务器可能主要受IO限制。您通常会发现执行以下操作更具效果:

CREATE TABLE main_table_new LIKE main_table;
ALTER TABLE main_table_new ADD COLUMN location varchar(256);
INSERT INTO main_table_new (fields_in_main_table) SELECT * FROM main_table;
RENAME TABLE main_table TO main_table_old, main_table_new TO main_table;
DROP TABLE main_table_old;

这样你就可以在空表上添加列,并且基本上在新表中写入数据,你确定没有其他人会在没有锁定太多资源的情况下查看。

答案 1 :(得分:22)

我认为适当的答案是使用pt-online-schema-changegh-ost等功能。

我们已经完成了超过40亿行的迁移,但这可能需要长达10天,停机时间不到一分钟。

Percona的工作方式与上述非常相似

  • 创建临时表
  • 在第一个表上创建触发器(用于插入,更新,删除),以便将它们复制到临时表
  • 小批量迁移数据
  • 完成后,将表重命名为新表,然后删除另一个表

答案 2 :(得分:0)

Alter table需要花费很长时间来处理像你这样的大数据,所以在这种情况下避免使用它,并使用像这样的代码:

select main_table.*, 
  cast(null as varchar(256)) as null_location, -- any column you want accepts null
  cast('' as varchar(256)) as not_null_location, --any column doesn't accept null
  cast(0 as int) as not_null_int, -- int column doesn't accept null
into new_table 
from main_table;

drop table main_table;
rename table new_table TO main_table;

答案 3 :(得分:0)

您可以通过暂时关闭唯一检查和外键检查来加快进程。您还可以更改使用的算法。

如果您希望新列位于表的末尾,则应使用 algorithm=instant:

SET unique_checks = 0;
SET foreign_key_checks = 0;
ALTER TABLE main_table ADD location varchar(256), algorithm=instant;
SET unique_checks = 1;
SET foreign_key_checks = 1;

否则,如果您需要该列位于特定位置,请使用 algorithm=inplace

SET unique_checks = 0;
SET foreign_key_checks = 0;
ALTER TABLE main_table ADD location varchar(256) AFTER othercolumn, algorithm=inplace;
SET unique_checks = 1;
SET foreign_key_checks = 1;

作为参考,我的 PC 用了大约 2 分钟的时间使用就地算法更改一个包含 2000 万行的表。如果您使用的是 Workbench 之类的程序,那么您可能需要在开始操作之前增加设置中的默认超时时间。

如果您发现操作无限期挂起,那么您可能需要查看进程列表并杀死表上有锁定的任何进程。您可以使用以下命令执行此操作:

SHOW FULL PROCESSLIST;
KILL PROCESS_NUMBER_GOES_HERE;

答案 4 :(得分:-1)

DB2 z/OS 立即对列进行虚拟添加。并将表置于咨询重组状态。在重组之前运行的任何内容都将获得默认值,如果没有默认值,则为 null。更新完成后,它们会展开更新的行。插入已完成扩展。下一次重组将展开每个未展开的行,并为其展开的任何内容分配默认值。

只有真正的数据库才能很好地处理这个问题。 DB2 z/OS。