MySQL/MariaDB storage engines: moving to InnoDB#
This page does not cover installing MySQL itself - for that, see the MySQL install page in the Linux Administration Book. What's here is a narrow but common question: a table (or an entire old database) is still on MyISAM, and you need to move it to InnoDB.
Why InnoDB#
InnoDB has been MySQL's default storage engine since 5.5 - if you are still seeing MyISAM, that table was probably created on a very old version or restored from an old backup. The difference is not cosmetic:
| MyISAM | InnoDB | |
|---|---|---|
| Transactions (COMMIT/ROLLBACK) | No | Yes |
| Locking | Table-level | Row-level |
| Crash recovery | Weak, tables corrupt often | Automatic |
| Foreign keys | Not supported | Supported |
| Full-text index | Yes (historically the one reason to stay) | Since MySQL 5.6+ |
If full-text search was your only reason to stay on MyISAM, InnoDB has had it for over a decade now - there is usually no remaining reason to keep it.
Check your current state#
SELECT table_schema, table_name, engine
FROM information_schema.tables
WHERE table_schema NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')
AND engine != 'InnoDB';
This lists every table in your system that is not using InnoDB.
Convert a single table#
ALTER TABLE database.table_name ENGINE=InnoDB;
Instant on small tables. On large tables ALTER TABLE rewrites the table and the time grows with its size - how much locking that involves depends on your MySQL/MariaDB version and which ALGORITHM/LOCK options it supports: ALGORITHM=COPY rebuilds the table from scratch and usually needs stronger locking, while ALGORITHM=INPLACE with LOCK=NONE may allow concurrent writes where it's supported.
Check locking before you assume it
Don't assume writes wait for the entire conversion, or that they can continue uninterrupted either way - verify which ALGORITHM/LOCK options your version supports beforehand (try ALTER TABLE ... ALGORITHM=INPLACE, LOCK=NONE or check EXPLAIN) and watch metadata locks while it runs. For a table with millions of rows, if the native operation can't meet your locking needs, do it during a low-traffic window or use an online tool like Percona Toolkit's pt-online-schema-change.
Convert an entire database#
Instead of writing each one by hand, generate the ALTER TABLE statements from information_schema and run them:
mysql -N -e "SELECT CONCAT('ALTER TABLE \`', REPLACE(table_schema, '\`', '\`\`'), '\`.\`', REPLACE(table_name, '\`', '\`\`'), '\` ENGINE=InnoDB;')
FROM information_schema.tables
WHERE table_schema='database_name' AND engine != 'InnoDB';" | mysql database_name
The backtick-quoting is not decoration: a table/database name with a reserved word, space, or hyphen breaks an unquoted ALTER TABLE statement, and the generated script stops right there - the remaining tables are silently left unconverted.
Back up before converting
ALTER TABLE ENGINE= is not reversible - if something goes wrong mid-conversion, you are left with neither the old nor the new format intact. Do not start a large conversion without a mysqldump backup first.
mysqldump database_name > /opt/backup/before-$(date +%F).sql
Make new tables default to InnoDB#
Set the server-wide default engine so this does not happen again:
[mysqld]
default_storage_engine = InnoDB
sudo systemctl restart mysql # or mariadb
With Morpheus
"list tables in database X that are not InnoDB"
"convert table Y to InnoDB, back up first"
Morpheus runs the query, shows you the result, and applies the conversion with your approval - but it does not skip the backup before a large conversion.
Checklist#
- [ ] Took a
mysqldumpbackup before converting - [ ] Converted large tables during a low-traffic window
- [ ] Set
default_storage_engine = InnoDBso this does not recur - [ ] Verified the application actually works after conversion (test anything relying on foreign keys or transactions)