MySQL:从大表中删除列

时间:2014-04-19 18:23:30

标签: mysql sql phpmyadmin

我有这么大的表,有三列:

+-----+-----+----------+
| id1 | id2 | associd  |
+-----+-----+----------+
|   1 |  38 | 73157604 |
|   1 | 112 | 73157605 |
|   1 | 113 | 73157606 |
|   1 | 198 | 31936810 |
|   1 | 391 | 73157607 |
+-----+-----+----------+

这持续38米行。问题是我想删除'associd'列,但运行ALTER TABLE table_name DROP COLUMN associd;只需要太长时间。我想做一些类似的事情:ALTER TABLE table_name SET UNUSED associd;ALTER TABLE table_name DROP UNUSED COLUMNS CHECKPOINT 250;然后显然加快了这个过程,但it isn't possible in MySQL?

是否有替代方法可以删除此列 - 可能只创建一个只包含两列的新表或者使用检查点进行删除?谢谢!

4 个答案:

答案 0 :(得分:31)

你所做的任何事情都需要读取和写入38米的行,所以没有什么是真正的快速。可能最快的方法可能是将数据放入新表中:

create table newTable as
    select id1, id2
    from oldTable;

或者,如果您想确保保留类型和索引:

create table newTable like oldTable;

alter table newTable drop column assocId;

insert into newTable(id1, id2)
    select id1, id2
    from oldTable;

但是,在加载一堆数据然后重新创建索引之前,通常会更快地删除表上的所有索引。

答案 1 :(得分:2)

免责声明:这个答案是面向MySQL的,可能不适用于其他数据库。

我认为在接受的答案中有一些缺失,我试图在这里公开一个通用序列,用于在生产环境中执行此类操作,不仅用于添加/删除列,还用于添加索引示例

我们称之为the Indiana Jones' movement

创建新表

使用旧表作为模板的新表:

create table my_table_new like my_table;

删除新表中的列

在新表中:

alter table my_table_new drop column column_to_delete;

将外键添加到新表

不会在create table like命令中自动生成。

您可以查看实际的外键:

mysql> show create table my_table;

然后将它们应用于新表:

alter table my_table_new
  add constraint my_table_fk_1 foreign key (field_1) references other_table_1 (id),
  add constraint my_table_fk_2 foreign key (field_2) references other_table_2 (id)

克隆表

复制除要删除的字段之外的所有字段。

我使用where句子可以在必要时多次运行此命令。

由于我认为这是一个生产环境,my_table将不断有新记录,因此我们必须保持同步,直到我们能够更改名称。

此外,我添加了limit,因为如果表格太大且索引太重,那么一次性克隆可能会关闭数据库的性能。另外,如果在流程的中间你要取消操作,它必须回滚所有已经完成的插入,这意味着你的数据库不会立即被恢复(https://dba.stackexchange.com/questions/5654/internal-reason-for-killing-process-taking-up-long-time-in-mysql

insert my_table_new select field_1, field_2, field_3 from my_table 
where id > ifnull((select max(id) from my_table_new), 0)
limit 100000; 

正如我多次这样做,我创建了一个程序:https://gist.github.com/fguillen/5abe87f922912709cd8b8a8a44553fe7

更改名称

确保在复制表中的最后一条记录后立即运行此命令。理想的是立即运行所有命令。

rename table my_table to my_table_3;
rename table my_table_new to my_table;

删除旧表

确保在执行此操作之前备份;)

drop table my_table_3

免责声明:我不确定是否会发生指向旧表的外键。

答案 2 :(得分:0)

在这种情况下,MySQL的最佳解决方案是:

1)将表Engine更改为MyISAM

2)更改您想要执行的任何操作(删除列,更改数据类型等)。

3)将其更改回InnoDB

在这种情况下,DBMS不会在每次记录迭代时都进行锁定/解锁。

但是请注意,如果您要在表/数据库中进行几项更改,那么此解决方案将是不错的选择,因为一旦将其还原回InnoDB,删除同一项将花费相同的时间柱。 因此,只有在数据库中要更改多个内容时,才考虑使用此解决方案。

答案 3 :(得分:0)

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

SET unique_checks=0;
SET foreign_key_checks=0;
ALTER TABLE table_name DROP COLUMN column_name, algorithm=inplace;
SET unique_checks=1;
SET foreign_key_checks=1;

使用上面的代码,我的电脑花了大约 2 分钟从一个 2000 万行的表中删除一列。

如果您使用的是 Workbench 之类的程序,那么您可能需要在开始操作之前增加设置中的默认超时时间。

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

SHOW FULL PROCESSLIST;
KILL PROCESS_NUMBER_GOES_HERE;