Quickest way to delete enormous MySQL table

MysqlInnodb

Mysql Problem Overview


I have an enormous MySQL (InnoDB) database with millions of rows in the sessions table that were created by an unrelated, malfunctioning crawler running on the same server as ours. Unfortunately, I have to fix the mess now.

If I try to truncate table sessions; it seems to take an inordinately long time (upwards of 30 minutes). I don't care about the data; I just want to have the table wiped out as quickly as possible. Is there a quicker way, or will I have to just stick it out overnight?

Mysql Solutions


Solution 1 - Mysql

(As this turned up high in Google's results, I thought a little more instruction might be handy.)

MySQL has a convenient way to create empty tables like existing tables, and an atomic table rename command. Together, this is a fast way to clear out data:

CREATE TABLE new_foo LIKE foo;

RENAME TABLE foo TO old_foo, new_foo TO foo;

DROP TABLE old_foo;

Done

Solution 2 - Mysql

The quickest way is to use DROP TABLE to drop the table completely and recreate it using the same definition. If you have no foreign key constraints on the table then you should do that.

If you're using MySQL version greater than 5.0.3, this will happen automatically with a TRUNCATE. You might get some useful information out of the manual as well, it describes how a TRUNCATE works with FK constraints. http://dev.mysql.com/doc/refman/5.0/en/truncate-table.html

EDIT: TRUNCATE is not the same as a drop or a DELETE FROM. For those that are confused about the differences, please check the manual link above. TRUNCATE will act the same as a drop if it can (if there are no FK's), otherwise it acts like a DELETE FROM with no where clause.

EDIT: If you have a large table, your MariaDB/MySQL is running with a binlog_format as ROW and you execute a DELETE without a predicate/WHERE clause, you are going to have issues to keep up the replication or even, to keep your Galera nodes running without hitting a flow control state. Also, binary logs can get your disk full. Be careful.

Solution 3 - Mysql

The best way I have found of doing this with MySQL is:

DELETE from table_name LIMIT 1000;

Or 10,000 (depending on how fast it happens).

Put that in a loop until all the rows are deleted.

Please do try this as it will actually work. It will take some time, but it will work.

Solution 4 - Mysql

Couldn't you grab the schema drop the table and recreate it?

Solution 5 - Mysql

drop table should be the fastest way to get rid of it.

Solution 6 - Mysql

Have you tried to use "drop"? I've used it on tables over 20GB and it always completes in seconds.

Solution 7 - Mysql

If you just want to get rid of the table altogether, why not simply drop it?

Solution 8 - Mysql

Truncate is fast, usually on the order of seconds or less. If it took 30 minutes, you probably had a case of some foreign keys referencing the table you were truncating. There may also be locking issues involved.

Truncate is effectively as efficient as one can empty a table, but you may have to remove the foreign key references unless you want those tables scrubbed as well.

Solution 9 - Mysql

We had these issues. We no longer use the database as a session store with Rails 2.x and the cookie store. However, dropping the table is a decent solution. You may want to consider stopping the mysql service, temporarily disable logging, start things up in safe mode and then do your drop/create. When done, turn on your logging again.

Solution 10 - Mysql

I'm not sure why it's taking so long. But perhaps try a rename, and recreate a blank table. Then you can drop the "extra" table without worrying how long it takes.

Solution 11 - Mysql

searlea's answer is nice, but as stated in the comments, you lose the foreign keys during the fight. this solution is similar: the truncate is executed within a second, but you keep the foreign keys.

The trick is that we disable/enable the FK checks.

SET FOREIGN_KEY_CHECKS=0;
CREATE TABLE NewFoo LIKE Foo;
insert into NewFoo SELECT * from Foo where What_You_Want_To_Keep  
    
truncate table Foo;
insert into Foo SELECT * from NewFoo;
SET FOREIGN_KEY_CHECKS=1;

Extended answer - Delete all but some rows

My problem was: Because of a crazy script, my table was for with 7.000.000 junk rows. I needed to delete 99% of data in this table, this is why i needed to copy What I Want To Keep in a tmp table before deleteting.

These Foo Rows i needed to keep were depending on other tables, that have foreign keys, and indexes.

something like that:

insert into NewFoo SELECT * from Foo where ID in (
 SELECT distinct FooID from TableA 
 union SELECT distinct FooID from TableB 
 union SELECT distinct FooID from TableC
)

but this query was always timing out after 1 hour. So i had to do it like this:

CREATE TEMPORARY TABLE tmpFooIDS  ENGINE=MEMORY  AS (SELECT distinct FooID from TableA);
insert into tmpFooIDS SELECT distinct FooID from TableB
insert into tmpFooIDS SELECT distinct FooID from TableC
insert into NewFoo SELECT * from Foo where ID in (select ID from tmpFooIDS);

I theory, because indexes are setup correctly, i think both ways of populating NewFoo should have been the same, but practicaly it didn't.

This is why in some cases, you could do like this:

SET FOREIGN_KEY_CHECKS=0;
CREATE TABLE NewFoo LIKE Foo;

-- Alternative way of keeping some data.
CREATE TEMPORARY TABLE tmpFooIDS  ENGINE=MEMORY  AS (SELECT * from Foo where What_You_Want_To_Keep);
insert into tmpFooIDS SELECT ID from Foo left join Bar where OtherStuff_You_Want_To_Keep_Using_Bar
insert into NewFoo SELECT * from Foo where ID in (select ID from tmpFooIDS);

truncate table Foo;
insert into Foo SELECT * from NewFoo;
SET FOREIGN_KEY_CHECKS=1;

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKyle KaitanView Question on Stackoverflow
Solution 1 - MysqlsearleaView Answer on Stackoverflow
Solution 2 - MysqlwompView Answer on Stackoverflow
Solution 3 - Mysqladnan.View Answer on Stackoverflow
Solution 4 - MysqlNateView Answer on Stackoverflow
Solution 5 - MysqlPaul SonierView Answer on Stackoverflow
Solution 6 - MysqlZenshaiView Answer on Stackoverflow
Solution 7 - MysqlshylentView Answer on Stackoverflow
Solution 8 - MysqlJeff FerlandView Answer on Stackoverflow
Solution 9 - MysqlBrian HoganView Answer on Stackoverflow
Solution 10 - MysqlBrent BaisleyView Answer on Stackoverflow
Solution 11 - MysqlXavierView Answer on Stackoverflow