85

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

ALTER TABLE main_table ADD COLUMN location varchar (256);

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

我试图用它mytop 来监控这个数据库的活动,以确保查询没有被其他查询进程锁定,但似乎没有。应该需要那么长时间吗?实际上,我只是在运行此命令之前重新启动了机器。现在这个命令仍在运行。我不知道该怎么办。

4

5 回答 5

200

您的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 SELECT *, NULL FROM main_table;
RENAME TABLE main_table TO main_table_old, main_table_new TO main_table;
DROP TABLE main_table_old;

通过这种方式,您可以在空表上添加列,并且基本上将数据写入该新表中,您确定没有人会在不锁定尽可能多的资源的情况下查看这些数据。

于 2011-09-29T15:21:00.427 回答
38

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

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

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

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

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;
于 2018-03-29T06:58:11.057 回答
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 使用就地算法更改了一个包含 2000 万行的表大约需要 2 分钟。如果您使用的是 Workbench 之类的程序,那么您可能希望在开始操作之前增加设置中的默认超时时间。

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

SHOW FULL PROCESSLIST;
KILL PROCESS_NUMBER_GOES_HERE;
于 2021-08-01T14:49:54.923 回答
-4

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

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

于 2021-06-16T21:42:16.310 回答