Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drop Column from Large Table

Tags:

sql

mysql

I have this largish table with three columns as such:

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

This continues for 38m rows. The problem is I want to remove the 'associd' column but running ALTER TABLE table_name DROP COLUMN associd; simply takes too long. I wanted to do something like: ALTER TABLE table_name SET UNUSED associd; and ALTER TABLE table_name DROP UNUSED COLUMNS CHECKPOINT 250; then which apparently speeds up the process but it isn't possible in MySQL?

Is there an alternative to remove this column-- maybe creating a new table with only the two columns or getting a drop with checkpoints?

like image 542
nico Avatar asked Apr 19 '14 18:04

nico


People also ask

Can I drop a column from a table?

SQL allows a user to remove one or more columns from a given table in the database if they are no longer needed or become redundant. To do so, the user must have ALTER permission on the object.

How do I drop a specific column in a table?

Right-click the column you want to delete and choose Delete Column from the shortcut menu. If the column participates in a relationship (FOREIGN KEY or PRIMARY KEY), a message prompts you to confirm the deletion of the selected columns and their relationships. Choose Yes.

How do you drop a column from a table in Oracle?

To physically drop a column you can use one of the following syntaxes, depending on whether you wish to drop a single or multiple columns. alter table table_name drop column column_name; alter table table_name drop (column_name1, column_name2);

How do you quickly delete a column in Oracle?

“If you are concerned about the length of time it could take to drop column data from all of the rows in a large table, you can use the ALTER TABLE...SET UNUSED statement.


2 Answers

Anything that you do is going to require reading and writing 38m rows, so nothing is going to be real fast. Probably the fastest method is probably to put the data into a new table:

create table newTable as     select id1, id2     from oldTable; 

Or, if you want to be sure that you preserve types and indexes:

create table newTable like oldTable;  alter table newTable drop column assocId;  insert into newTable(id1, id2)     select id1, id2     from oldTable; 

However, it is usually faster to drop all index on a table before loading a bunch of data and then recreate the indexes afterwards.

like image 62
Gordon Linoff Avatar answered Sep 24 '22 14:09

Gordon Linoff


Disclaimer: this answer is MySQL oriented and might not work for other databases.

I think in the accepted answer there are some things missing, I have tried to expose here a generic sequence I use to do this kind of operations in a production environment, not only for adding/removing columns but also to add indexes for example.

We call it the Indiana Jones' movement.

Create a new table

A new table using the old one as template:

create table my_table_new like my_table; 

Remove the column in the new table

In the new table:

alter table my_table_new drop column column_to_delete; 

Add the foreign keys to the new table

The are not generate automatically in the create table like command.

You can check the actual foreign keys:

mysql> show create table my_table; 

Then apply them to the new 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) 

Clone the table

Copy all fields but the one you want to delete.

I use a where sentence to be able to run this command many times if necessary.

As I suppose this is a production environment the my_table will have new records continuously so we have to keep synchronizing until we are capable to do the name changing.

Also I have added a limit because if the table is too big and the indexes are too heavy making a one-shot clone can shut down the performance of your database. Plus, if in the middle of the process you want to cancel the operation it will must to rollback all the already done insertions which means your database won't be recovered instantly (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;  

As I was doing this several times I created a procedure: https://gist.github.com/fguillen/5abe87f922912709cd8b8a8a44553fe7

Do the name changing

Be sure you run this commands inmediately after you have replicate the last records from your table. Idealy run all commands at once.

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

Delete the old table

Be sure you have a back up before you do this ;)

drop table my_table_3 

Disclaimer: I am not sure what will happen with foreign keys that were pointing to the old table.

like image 33
fguillen Avatar answered Sep 23 '22 14:09

fguillen