How to reduce MySQL ibdata when you're out of space

Verze pro tiskPDF verze

You can easily jump into troubles if you're using MySQL InnoDB storage engine in its default configuration (which is most used setup). It is absurd that there is not built-in function to compact ibdata file. This is something that I don't fully understand, but you simply can't delete space/transactions in this file and only acceptable (not reasonable) answer which I have found has been related to performance impact when file needs to be expanded...
The only way how you can reduce size of ibdata is database/table export which you will import back. BUT you're already out of space so how to do it?

// Imagine this scenario

Server A - MySQL server, out of space
Server B - standard Linux box with free space

You will see how powerful netcat can be :]

// Reducing ibdata

1] Kill all daemons which can use MySQL

(Apache, application, etc.) on server A

2] Dump MySQL database

If you're not using innodb_file_per_table = 1 dump all data and send output via network to our server B.

On server B will listen netcat on port 12345

[]$ nc -l -p 12345 > /var/enough-space/mysql-export-all.sql

On server A we will export all databases to stdout which is handled by netcat and sent to our server B on port 12345 (use parameters to authorize this if needed)

[]$ mysqldump --extended-insert --all-databases --add-drop-database --disable-keys --flush-privileges --quick --routines --triggers --skip-lock-tables --force | nc 12345 will take some time, depend on size of your database. Netcat will stop listening when transfer is completed

3] Delete all files inside datadir on server A

[usually /var/lib/mysql/]

[]$ rm -rf /var/lib/mysql/ && mkdir /var/lib/mysql/

4] Initialize MySQL on server A

Update your /etc/my.cnf with option

innodb_file_per_table = 1
which will create innodb file for each table.
[]$ sudo -u mysql mysql_install_db
[]$ chown -R mysql.mysql /var/lib/mysql
# Start MySQL
[]$ /etc/init.d/mysqld start

5] Create FIFO file and import database

At this moment we can't simply transfer SQL file back and import it into server, because size of file together with size of newly imported data from file will fill the disk again. So we will create special file which is working in same way as fifo buffer to which we will send stdout of netcat.

# Create FIFO
[]$ mknod /var/fifo-buffer p

# Netcat will listen on port 54321 and send everything to FIFO
[]$ nc -l -p 54321 > /var/fifo-buffer

# Go into mysql console
[]$ mysql
mysql> SOURCE /var/fifo-buffer;       # during this step mysql waiting on data from buffer
mysql> quit

# Now we will send data from server B to server A
[]$ cat /var/enough-space/mysql-export-all.sql | nc 54321

As usual netcat will stop listening when transfer is completed and you're done!!

Few tips

First of all please consider if you can't move forward and use Percona MySQL which is back-compatible with MySQL, brings a lot of new features, high performance, better memory usage, more scalability on many cores and last but not least evolution replacement of InnoDB called XtraDB.

You can also move second ibdata file to different disk when reached defined size in standard data home dir.
example /etc/my.cnf

innodb_data_file_path = ibdata1:200M;/disk2/ibdata2:50M:autoextend

This will create 200M file in default data home dir (innodb_data_home_dir), when this size is reached next 50M ibdata file will be created on /disk2/ibdata2 and autoextended when needed. This should be local disk or SAN. In case of NFS you will hit performance bottleneck.


InnoDB Configuration -
Percona XtraDB Storage Engine for MySQL -
Percona Server Feature Comparison -
Percona Server with XtraDB -