Reclaiming Your InnoDB Tablespace
Published October 29th, 2008Problem Statement:
When you use InnoDB table engine for tables that require concurrent INSERT/UPDATE type of access, you need to be careable about the table space used by InnoDB engine by default. It appears that by default, MySQL creates the InnoDB tables in a single tablespace file called /var/lib/mysql/ibdata1.
Unfortunately, as you use your InnoDB tables the size of the table space file continues to grow even when you delete records or truncate one or more InnoDB tables. There is no easy way to recover this space using some vaporware innodb defragmentation tool.
Here we will discuss two solutions that we have used in the recent past.
Solution A: Dealing with Your Future InnoDB Tables
If you have not yet used InnoDB but planning to start soon, you are in good shape! You can simply tell MySQL to create separate tablespace files for each of your tables; this gives you much more control over deleting such files when you no longer need the table in a specific database. Here is how you can setup MySQL to create individual InnoDB tablespace files for each of your future InnoDB tables:
- Edit your /etc/my.cnf MySQL configuration file to have innodb_file_per_table in the [mysqld] section
- Now create a new InnoDB table in one of your database
- Check the /var/lib/mysql/<yourdatabase>/ directory and you will notice a new InnoDB tablespace file
Solution B: Dealing with Your Existing InnoDB Tables
When you already have a large /var/lib/myslq/ibdata1 file, you are in a bit of a maintenance pickle. Your option is as follows:
- Backup your database as-is
- Temporarily, alter your InnoDB table engine from InnoDB to MYISAM
- Dump your database
- Drop the database
- Stop MySQL server
- Move your /var/lib/mysql/ibdata1 file out of your MySQL server
- Restart MySQL
- Recreate the database
- Reload your tables from your MySQL dump file
For example, say you have a database called my_db and you want to reclaim the disk space lost due to the ever growing ibdata1 file.
Here is what you would do:
- Backup using:
mysqldump -u root -p --opt my_db > my_db.as-is.sql - Change InnoDB tables to MYISAM using:
ALTER TABLE [tablename] TYPE=MYISAM - Like the first step, create a dump called
my_db.dump.sqlusing mysqldump command - Drop your database using:
DROP database my_db - Stop MYSQL server using:
service mysql stop - Move the
/var/lib/mysql/ibdata1file out of your MySQL server space - Start MySQL server using:
service mysql start - Recreate the database using:
create database my_db - Load data to your database using:
mysql -u root -p -D my_db < my_db.dump.sql - Alter the table engine back to
ALTER TABLE [tablename] TYPE=INNODB
| Disclaimer |
| Please make sure you take extra care to backup your database before you perform the above-mention steps. We are never responsible for any data loss. All your actions are your responsibility. |
Pranab on April 23, 2009
MySQL should come up with some solution. Space reclaim facility is not available. This problem is submitted as bug, hope in near future MySQL will be equipped with free space reclaim feature.
Tom P. on August 27, 2009
It’s very unclear what is gained by altering the table engine for every table in your database and then taking a second backup. Why can’t I recreate my database from the first backup?
FWIW, I’m just hitting this issue after several years of use but it is a very serious shortcoming. Posts over 5 years old on the MySql web site but nothing yet. Why?
Andrew Poodle on December 7, 2009
@TomP,
With regards to MySQL not doing anything to aid the issue, you need to remember that InnoDB is the product of Innobase, an Oracle company, and it’s up to them how the datafiles are managed. Try Falcon or Maria
Like you, I don’t see any benefit in the second backup. However, I’d do it differently depending on space and resources available.
Stop connections to the database.
Then either…
Dump the database data only, one datafile for each table.
Dump the database structure only with “drop tables” enabled.
Reload the database from the structure file, this will drop and re-create the tables.
Load the data from the dump files.
OR…
for each table, create a new table, table_new.
The insert into table_new select * from table
rename table to table_old,table_new to table.
The benefit of the second approach is that if you’re clever, you can tailor the inserts to include only data that your system needs initially, to speed deployment, then load across older data as time goes on, and that it can be done (at a push) on a live system, but it is, ultimately, slower.
Glenn Plas on April 6, 2010
Hi All,
Please note that when using separate tablespace files for each of your tables you will need A LOT MORE diskspace than when they are in 1 innodb file. I noticed this the hard way running out of disk space and I wasn’t even halfway the restore process.
It’s my guess that using per-table-innodb file will use about 2 to 4 times the space you’d normally use. I have plenty of tables which is probably a factor but since most admin here are looking for a way to reclaim disk space I guess they are almost out, then this options would probably backfire at some point.