In MySQL, when you are using InnoDB, all the tables and indexes are stored under the MySQL system tablespace.
MySQL system tablespace is ibdata1, which is located under /var/lib/mysql
The single ibdata1 file contains all the tables and indexes in your MySQL database. So, if you have a big database, this file size will grow really big.
In this tutorial, we’ll explain how to rebuild your entire MySQL database, and break the big MySQL system tablespace file into small individual MySQL table files.
Take this scenario as an example: You’ve uploaded 100GB worth of data into multiple tables in your MySQL.
Now, the ibdata1 file size will be around 100GB+.
In the above case, later when you add 10GB worth of data to the tables, the ibdata1 file size doesn’t grow to 110GB, and stays at 100GB. Because, the file still has the unused space inside from the above 50GB of deleted data.
The problem is, you can’t reclaim those unused space after you delete the 50GB of data from ibdata1 file. There is a way to do it, but is too complicated (explained below), and involves taking the MySQL database down.
So, how do we avoid storing all the tables and indexes in a single ibdata1 file; instead store in multiple table files individually?
In this example, on CentOS 6, the default MySQL that you get when installing from yum repository is still 5.1.73 as shown below.
Anytime you make any changes to my.cnf, you should restart the MariaDB MySQL database.
In this example, I created a new table called employee and uploaded around 20GB worth of data into it.
First, it will create a subdirectory with the database name “database” under the /var/lib/mysql directory
Let us say you have a table called benefits under database. This benefits table was created before we set the innodb_file_per_table in the my.cnf.
So, the benefits table will still be under ibdata1 file. To move this out of ibdata1 into it’s own IBD file, we have to optimize the table as shown below.
Now ibdata1 will be only few MB in size. All the database tables will be stored as individual files under the corresponding database subdirectory under /var/lib/mysql/
MySQL system tablespace is ibdata1, which is located under /var/lib/mysql
The single ibdata1 file contains all the tables and indexes in your MySQL database. So, if you have a big database, this file size will grow really big.
In this tutorial, we’ll explain how to rebuild your entire MySQL database, and break the big MySQL system tablespace file into small individual MySQL table files.
1. Big MySQL (and MariaDB) System Tablespace
There is a major drawback with the default big MySQL system tablespace approach.Take this scenario as an example: You’ve uploaded 100GB worth of data into multiple tables in your MySQL.
Now, the ibdata1 file size will be around 100GB+.
# cd /var/lib/mysql # ls -lh ibdata1 -rw-r-----. 1 mysql mysql 101G Jan 21 21:10 ibdata1After few days, you deleted around 50GB worth of data from all those tables. The ibdata1 file size will not be reduced to around 50GB+, it will still stay at around 100GB+.
In the above case, later when you add 10GB worth of data to the tables, the ibdata1 file size doesn’t grow to 110GB, and stays at 100GB. Because, the file still has the unused space inside from the above 50GB of deleted data.
The problem is, you can’t reclaim those unused space after you delete the 50GB of data from ibdata1 file. There is a way to do it, but is too complicated (explained below), and involves taking the MySQL database down.
So, how do we avoid storing all the tables and indexes in a single ibdata1 file; instead store in multiple table files individually?
2. Set the innodb_file_per_table parameter
For this, you should use innodb_file_per_table parameter inside your /etc/my.cnf file under the “mysqld” section as shown below:# vi /etc/my.cnf [mysqld] innodb_file_per_tableNote: If you are using MySQL 5.6.6 (or MariaDB) and higher, the above is the default setting.
In this example, on CentOS 6, the default MySQL that you get when installing from yum repository is still 5.1.73 as shown below.
# mysql --version mysql Ver 14.14 Distrib 5.1.73, for redhat-linux-gnu (x86_64) using readline 5.1So, in this case, we should set the innodb_file_per_table in the my.cnf file.
Anytime you make any changes to my.cnf, you should restart the MariaDB MySQL database.
service mysqld restartNote: For some reason if you want to set this parameter while the database is running, and don’t want to shutdown MariaDB, you can do the following set global from the mysql prompt.
mysql> set global innodb_file_per_table=1;
3. New Tables (and index) as individual files
From now on, when you create a new MySQL table, you’ll get individual files.In this example, I created a new table called employee and uploaded around 20GB worth of data into it.
mysql> use database mysql> create table employee ... mysql> insert into employee ..Two things will happen here:
First, it will create a subdirectory with the database name “database” under the /var/lib/mysql directory
# ls -l /var/lib/mysql/ drwx------. 2 mysql mysql 266240 Jan 5 12:11 database ..Second, under this database directory name (i.e under database directory), you’ll see individual file EMPLOYEE.IBD getting created. The
size of this file will be the size of the data that you uploaded only to that table. In this case, since we uploaded 20GB worth of data into this table, the EMPLOYEE.IBD filesize is around 20GB as shown below.
# cd /var/lib/mysql/database/ # ls -lh -rw-r-----. 1 mysql mysql 21G Jan 21 21:17 employee.ibdNote: If you are using MyISAM database, you’ll see individual .MYD, .FRM and .MYI files
4. Extract existing tables from ibdata1
Next, if you want to extract an existing table from ibdata1 to it’s own individual file, then you have to optimize the table.Let us say you have a table called benefits under database. This benefits table was created before we set the innodb_file_per_table in the my.cnf.
So, the benefits table will still be under ibdata1 file. To move this out of ibdata1 into it’s own IBD file, we have to optimize the table as shown below.
mysql> use database mysql> optimize table benefits;This will create the following individual file for the benefits table.
# cd /var/lib/mysql/database/ # ls -lh -rw-r-----. 1 mysql mysql 21G Jan 21 21:17 benefits.ibdIn this example, keep in mind that the original ibdata1 file still did not shrink. It is still around 100GB.
# ls -lh /var/lib/mysql/ibdata1 -rw-r-----. 1 mysql mysql 101G Jan 21 21:10 ibdata1Note: You can also do the following.
mysql> alter table benefits engine=InnoDB;
5. Shrink ibdata1 File Size
Keep in mind that the ibdata1 still remains the same 101G size, it didn’t reduce the size yet.# ls -lh /var/lib/mysql/ibdata1 -rw-r-----. 1 mysql mysql 101G Jan 21 21:10 ibdata1To shrink the ibdata1 file, you need to perform the following steps:
6. Backup the Database
First, temporarily stop mysql database, and take a cold backup of the whole database. In case something goes wrong, you can use this cold backup to restore.mkdir /backup cd /var/lib cp -r mysql /backupSecond, take a mysqldump backup of all the database.
mysqldump -u root -ptmppassword --all-databases > /backup/all-database.sql
7. Drop all your database
Next, drop all your database one by one. To view all the database to be dropped, use “show databases”mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | database | | sales | | mysql | +--------------------+In this example, we are dropping two databases (database and sales) that exist in the mysql.
# mysql -u root -ptmppassword mysql> drop database database; mysql> drop database sales;Note: Do not drop information_schema and mysql database.
8. Delete ibdata and ib_logfile
Next, shutdown the MySQL database.service mysqld stopNext, remove the ibdata1 file and all the individual ib_logfile* files:
cd /var/lib/mysql/ rm ibdata1 rm ib_logfile0 rm ib_logfile1
9. Import all the Database
Note: At this point, you should already have the following in your my.cnf file.[mysqld] innodb_file_per_tableStart the MySQL database.
service mysqld startImport all the database from the mysqldump backup that we took earlier.
mysql -u root -ptmppassword --all-databases < /backup/all-database.sqlAt this stage, the ibdata1 file, which is the MySQL system tablespace will be created from scratch, and in our example, it will not be 100GB anymore.
Now ibdata1 will be only few MB in size. All the database tables will be stored as individual files under the corresponding database subdirectory under /var/lib/mysql/