MySQL – Converting to MyISAM with foreign_key_checks=0 Not Working

innodbmyisamMySQL

At the end of a long series of compromises working in a system I didn't design, own, or maintain, I need to convert a number of MySQL InnoDB tables to MyISAM tables. However, when I attempt to alter the table

mysql> ALTER TABLE catalog_category_entity ENGINE=MyISAM;
ERROR 1217 (23000): Cannot delete or update a parent row: a foreign key constraint fails
mysql>

MySQL complains. This is expected. However, if I disable the foreign_key_checks, I get the same results

mysql> SET foreign_key_checks = 0;
mysql> ALTER TABLE catalog_category_entity ENGINE=MyISAM;
ERROR 1217 (23000): Cannot delete or update a parent row: a foreign key constraint fails

This happens regardless of my setting the key check at the global or session level. I assume the problem here is the table in questions has other InnoDB table which reference it, and MySQL refuses to end up in a state where an InnoDB table references a table that's not InnoDB. (I may be incorrect on this, and I'm more than happy to be corrected)

Is there a quick way to handle this situation? I basically want all tables in the database to be MyISAM, and tracing out all the relationships myself and/or manually removing the contraints seems very time consuming, and the sort of thing that a computer would be better at.

If the answer is "suck it up and do the work" I'm happy to hear that from an expert — I just don't want to waste the time if I don't need to.

Best Answer

Here's a method you can use without dumping all your InnoDB tables.

You will have to drop the foreign key constraints before you can alter the tables. You can generate the drop statements using the INFORMATION_SCHEMA this way:

mysql> SELECT CONCAT('ALTER TABLE `', table_schema, '`.`', table_name, 
    '` DROP FOREIGN KEY `', constraint_name, '`;') AS _sql 
  FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE 
  WHERE referenced_table_schema = 'mydb' -- replace with your database name
    AND referenced_table_name = 'catalog_category_entity' 
    AND ordinal_position = 1;

The output should be one or more a fully-formed DDL statements. Run the statements, and then you can change the storage engine for your parent table.