When you create a table using the InnoDB storage engine, data written to that table is stored on the file system in a data file called a tablespace. Tablespace files contain both the data and indexes.
When innodb_file_per_table=ON
is set, InnoDB uses one tablespace file per InnoDB table. These tablespace files have the .ibd
extension. When innodb_file_per_table=OFF
is set, InnoDB stores all tables in the InnoDB system tablespace.
InnoDB versions in MySQL 5.7 and above also support an additional type of tablespace called general tablespaces that are created with CREATE TABLESPACE
. However, InnoDB versions in MariaDB Server do not currently support general tablespaces or CREATE TABLESPACE
.
By default, InnoDB's file-per-table tablespaces are created in the system's data directory, which is defined by the datadir
system variable. If you want to store InnoDB data separate from the data for other storage engines, then you change this by setting the the innodb_data_home_dir
system variable.
In the event that you have a specific tablespace that you need stored in a dedicated path, you can set the location using the DATA DIRECTORY
table option when you create the table.
For instance,
CREATE TABLE test.t1 ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) ) ENGINE=InnoDB DATA DIRECTORY = "/data/contact";
MariaDB then creates a database directory on the configured path and the file-per-table tablespace will be created inside that directory. On Unix-like operating systems, you can see the file using the ls command:
# ls -al /data/contact/test drwxrwx--- 2 mysql mysql 4096 Dec 8 18:46 . drwxr-xr-x 3 mysql mysql 4096 Dec 8 18:46 .. -rw-rw---- 1 mysql mysql 98304 Dec 8 20:41 t1.ibd
Note, the system user that runs the MariaDB Server process (which is usually mysql
) must have write permissions on the given path.
InnoDB's file-per-table tablespaces are transportable, which means that you can copy a file-per-table tablespace from one MariaDB Server to another server. You may find this useful in cases where you need to transport full tables between servers and don't want to use backup tools like mariabackup
or mysqldump
. In fact, this process can even be used with mariabackup
in some cases, such as when restoring partial backups or when restoring individual tables or partitions from a backup.
You can copy the transportable tablespace of a non-partitioned table from one server to another by exporting the tablespace file from the original server, and then importing the tablespace file into the new server.
You can export a non-partitioned table by locking the table and copying the table's .ibd
and .cfg
files from the relevant tablespace location for the table to a backup location. For example, the process would go like this:
FLUSH TABLES ... FOR EXPORT
statement on the target table: FLUSH TABLES test.t1 FOR EXPORT;
This forces the server to close the table and provides your connection with a read lock on the table.
# cp /data/contacts/test/t1.ibd /data/saved-tablespaces/ # cp /data/contacts/test/t1.cfg /data/saved-tablespaces/
UNLOCK TABLES
: UNLOCK TABLES;
You can import a non-partitioned table by discarding the table's original tablespace, copying the table's .ibd
and .cfg
files from the backup location to the relevant tablespace location for the table, and then telling the server to import the tablespace. For example, the process would go like this:
CREATE TABLE
statement that was used to create the table on the original server: CREATE TABLE test.t1 ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) ) ENGINE=InnoDB;
ALTER TABLE ... DISCARD TABLESPACE
to discard the new table's tablespace: ALTER TABLE test.t1 DISCARD TABLESPACE;
.ibd
and .cfg
files from the original server to the relevant directory on the target MariaDB Server: # scp /data/tablespaces/t1.ibd target-server.com:/var/lib/mysql/test/ # scp /data/tablespaces/t1.cfg target-server.com:/var/lib/mysql/test/
File-per-table tablespaces can be imported with just the .ibd
file in many cases. If you do not have the tablespace's .cfg
file for whatever reason, then it is usually worth trying to import the tablespace with just the .ibd
file.
ALTER TABLE ... IMPORT TABLESPACE
to import the new table's tablespace: ALTER TABLE test.t1 IMPORT TABLESPACE;
Currently, MariaDB does not directly support the transport of tablespaces from partitioned tables. See MDEV-10568 for more information about that. It is still possible to transport partitioned tables if we use a workaround. You can copy the transportable tablespaces of a partitioned table from one server to another by exporting the tablespace file of each partition from the original server, and then importing the tablespace file of each partition into the new server.
You can export a partitioned table by locking the table and copying the .ibd
and .cfg
files of each partition from the relevant tablespace location for the partition to a backup location. For example, the process would go like this:
CREATE TABLE test.t2 ( employee_id INT, name VARCHAR(50), ) ENGINE=InnoDB PARTITION BY RANGE (employee_id) ( PARTITION p0 VALUES LESS THAN (6), PARTITION p1 VALUES LESS THAN (11), PARTITION p2 VALUES LESS THAN (16), PARTITION p3 VALUES LESS THAN MAXVALUE ); INSERT INTO test.t2 (name, employee_id) VALUES ('Geoff Montee', 1), ('Chris Calendar', 6), ('Kyle Joiner', 11), ('Will Fong', 16);
FLUSH TABLES ... FOR EXPORT
statement on the target table: FLUSH TABLES test.t2 FOR EXPORT;
This forces the server to close the table and provides your connection with a read lock on the table.
t2
table, we can see a number of .ibd
and .cfg
files for the table: # ls -l /var/lib/mysql/test/ | grep t2 total 428 -rw-rw---- 1 mysql mysql 827 Dec 5 16:08 t2.frm -rw-rw---- 1 mysql mysql 48 Dec 5 16:08 t2.par -rw-rw---- 1 mysql mysql 579 Dec 5 18:47 t2#P#p0.cfg -rw-r----- 1 mysql mysql 98304 Dec 5 16:43 t2#P#p0.ibd -rw-rw---- 1 mysql mysql 579 Dec 5 18:47 t2#P#p1.cfg -rw-rw---- 1 mysql mysql 98304 Dec 5 16:08 t2#P#p1.ibd -rw-rw---- 1 mysql mysql 579 Dec 5 18:47 t2#P#p2.cfg -rw-rw---- 1 mysql mysql 98304 Dec 5 16:08 t2#P#p2.ibd -rw-rw---- 1 mysql mysql 579 Dec 5 18:47 t2#P#p3.cfg -rw-rw---- 1 mysql mysql 98304 Dec 5 16:08 t2#P#p3.ibd
$ mkdir /tmp/backup $ sudo cp /var/lib/mysql/test/*.ibd /tmp/backup $ sudo cp /var/lib/mysql/test/*.cfg /tmp/backup
UNLOCK TABLES
: UNLOCK TABLES;
You can import a partitioned table by creating a placeholder table, discarding the placeholder table's original tablespace, copying the partition's .ibd
and .cfg
files from the backup location to the relevant tablespace location for the placeholder table, and then telling the server to import the tablespace. At that point, the server can exchange the tablespace for the placeholder table with the one for the partition. For example, the process would go like this:
$ scp /tmp/backup/t2* user@target-host:/tmp/backup
CREATE TABLE test.t2 ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50), employee_id INT ) ENGINE=InnoDB PARTITION BY RANGE (employee_id) ( PARTITION p0 VALUES LESS THAN (6), PARTITION p1 VALUES LESS THAN (11), PARTITION p2 VALUES LESS THAN (16), PARTITION p3 VALUES LESS THAN MAXVALUE );
CREATE TABLE... AS SELECT
statement: CREATE TABLE test.t2_placeholder AS SELECT * FROM test.t2 WHERE NULL;
This statement will create a new table called t2_placeholder
that has the same schema structure as t2
, but it does not use partitioning and it contains no rows.
From this point forward, the rest of our steps need to happen for each individual partition. For each partition, we need to do the following process:
ALTER TABLE ... DISCARD TABLESPACE
to discard the placeholder table's tablespace: ALTER TABLE test.t2_placeholder DISCARD TABLESPACE;
.ibd
and .cfg
files for the next partition to the relevant directory for the t2_placeholder
table on the target MariaDB Server: # cp /tmp/backup/t2#P#p0.cfg /var/lib/mysql/test/t2_placeholder.cfg # cp /tmp/backup/t2#P#p0.ibd /var/lib/mysql/test/t2_placeholder.ibd # chown mysql:mysql /var/lib/mysql/test/t2_placeholder*
File-per-table tablespaces can be imported with just the .ibd
file in many cases. If you do not have the tablepace's .cfg
file for whatever reason, then it is usually worth trying to import the tablespace with just the .ibd
file.
ALTER TABLE ... IMPORT TABLESPACE
to import the new table's tablespace: ALTER TABLE test.t2_placeholder IMPORT TABLESPACE;
The placeholder table now contains data from the p0
partition on the source server.
SELECT * FROM test.t2_placeholder; +-------------+--------------+ | employee_id | name | +-------------+--------------+ | 1 | Geoff Montee | +-------------+--------------+
ALTER TABLE... EXCHANGE PARTITION
statement: ALTER TABLE test.t2 EXCHANGE PARTITION p0 WITH TABLE test.t2_placeholder;
The target table now contains the first partition from the source table.
SELECT * FROM test.t2; +-------------+--------------+ | employee_id | name | +-------------+--------------+ | 1 | Geoff Montee | +-------------+--------------+
When this process is complete for all partitions, the target table will contain the imported data:
SELECT * FROM test.t2; +-------------+----------------+ | employee_id | name | +-------------+----------------+ | 1 | Geoff Montee | | 6 | Chris Calendar | | 11 | Kyle Joiner | | 16 | Will Fong | +-------------+----------------+
DROP TABLE test.t2_placeholder;
MariaDB 10.1.2 added the mysql56_temporal_format
system variable, which enables a new MySQL 5.6-compatible storage format for the TIME
, DATETIME
and TIMESTAMP
data types.
If a file-per-tablespace file contains columns that use one or more of these temporal data types and if the tablespace file's original table was created with a certain storage format for these columns, then the tablespace file can only be imported into tables that were also created with the same storage format for these columns as the original table. Otherwise, you will see errors like the following:
ALTER TABLE dt_test IMPORT TABLESPACE; ERROR 1808 (HY000): Schema mismatch (Column dt precise type mismatch.)
See MDEV-15225 for more information.
See the pages for the TIME
, DATETIME
and TIMESTAMP
data types to determine how to update the storage format for temporal columns in tables that were created before MariaDB 10.1.2 or that were created with mysql56_temporal_format=OFF
.
InnoDB file-per-table tablespaces can use different row formats. A specific row format can be specified when creating a table either by setting the ROW_FORMAT
table option or by the setting the innodb_default_row_format
system variable. See Setting a Table's Row Format for more information on how to set an InnoDB table's row format.
If a file-per-tablespace file was created with a certain row format, then the tablespace file can only be imported into tables that were created with the same row format as the original table. Otherwise, you will see errors like the following:
ALTER TABLE t0 IMPORT TABLESPACE; ERROR 1808 (HY000): Schema mismatch (Expected FSP_SPACE_FLAGS=0x21, .ibd file contains 0x0.)
The error message will be a bit more descriptive in MariaDB 10.2.17 and later:
ALTER TABLE t0 IMPORT TABLESPACE; ERROR 1808 (HY000): Schema mismatch (Table flags don't match, server table has 0x1 and the meta-data file has 0x0; .cfg file uses ROW_FORMAT=REDUNDANT)
Be sure to check a tablespace's row format before moving it from one server to another. Keep in mind that the default row format can change between major versions of MySQL or MariaDB. See Checking a Table's Row Format for information on how to check an InnoDB table's row format.
See MDEV-15049 and MDEV-16851 for more information.
DISCARD on a table with foreign key constraints is only possible after disabling foreign_key_checks:
SET SESSION foreign_key_checks=0; ALTER TABLE t0 DISCARD TABLESPACE;
IMPORT on the other hand does not enforce foreign key constraints. So when importing tablespaces, referential integrity can only be guaranteed to import all tables bound by foreign key constraint at the same time, from an EXPORT of those tables taken with the same transactional state.
MariaDB supports data-at-rest encryption for the InnoDB storage engine. When enabled, the Server encrypts data before writing it to the tablespace and decrypts reads from the tablespace before returning result-sets. This means that a malicious user attempting to exfiltrate sensitive data won't be able to import the tablespace onto a different server as shown above without the encryption key.
For more information on data encryption, see Encrypting Data for InnoDB.
© 2019 MariaDB
Licensed under the Creative Commons Attribution 3.0 Unported License and the GNU Free Documentation License.
https://mariadb.com/kb/en/innodb-file-per-table-tablespaces/