Does MySQL do automatic indexing for foreign keys? - mysql

Can anyone tell me if MySQL does indexing for its foreign keys automatically or not?
My MySQL is using MyIsam Engine.

MyISAM does not support foreign keys at all. From the manual:
For storage engines other than InnoDB, MySQL Server parses the FOREIGN
KEY syntax in CREATE TABLE statements, but does not use or store it.
... At a later stage, foreign key constraints will be implemented for
MyISAM tables as well.
This is for MySQL 5.6, the next version, so it is not implemented yet. The text is exactly the same for older versions.
This means that the foreign key construct is not used at all. You can specify it in your CREATE TABLE command but MySQL will silently ignore it. No index will be made out of it, and it won't be stored (so a SHOW CREATE TABLE command will not show that you tried to createa a foreign key).
If you need foreign key support, consider using the InnoDB storage engine instead. InnoDB creates indices automatically for foreign keys.

MyISAM engine doesn't support foreign keys, only the InnoDB engine:
http://dev.mysql.com/doc/refman/5.5/en/innodb-foreign-key-constraints.html
InnoDB requires indexes on foreign keys and referenced keys so that
foreign key checks can be fast and not require a table scan. In the
referencing table, there must be an index where the foreign key
columns are listed as the first columns in the same order. Such an
index is created on the referencing table automatically if it does not
exist. This index might be silently dropped later, if you create
another index that can be used to enforce the foreign key constraint.
index_name, if given, is used as described previously.

Related

What to do with the auto-created index when applying a foreign key constraint in MySQL?

When a foreign key constraint is placed on on a MySQL table, an index is automatically added by MySQL for better performance. I'm totally ok with this. It's all in the docs.
But, when deleting the foreign key, I noticed that the auto-created index itself is not deleted. And that's not in de docs. I'm wondering:
Will it get ever deleted automatically, since MySQL did create it for me too?
How large can a foreign key index get? If it's only a few kilobytes, I'm not bothered, but what if it gets large...?
https://dev.mysql.com/doc/refman/8.0/en/create-table-foreign-keys.html only says this:
MySQL requires indexes on foreign keys and referenced keys so that
foreign key checks can be fast and not require a table scan. In the
referencing table, there must be an index where the foreign key
columns are listed as the first columns in the same order. Such an
index is created on the referencing table automatically if it does not
exist. This index might be silently dropped later if you create
another index that can be used to enforce the foreign key constraint.
index_name, if given, is used as described previously.
A foreign key index is just like a regular secondary index. It will grow proportionally to the number of rows in the table, and the data type in the indexed column(s).
It might still be useful to have this index if you run queries that need it. It's common in MySQL deployments to avoid foreign key constraints, but keep the indexes to support optimizing joins or searches.
If you don't need that index, i.e. if you have no queries that use the index, then you can drop it.

Can a foreign key use unique index?

I created a unique index on a column, and then added a foreign key using ALTER TABLE. MySQL added a non-unique index on top of my unique index to the column. Is the non-unique index necessary? Does it speed things up in any way?
Does it speed things up in any way?
First, Indexes do not always speed things up. Indexes are slowing down update, insert and delete statements, because the index has to be updated along with the data.
Second, there are scenarios, where the mysql-optimizer might decide to use a wrong index, and using another Index might be faster.
Is the non-unique index necessary?
No. See also the mysql documentation about YOUR usecase, if you would have done it the other way round:
http://dev.mysql.com/doc/refman/5.6/en/create-table-foreign-keys.html
MySQL requires indexes on foreign keys and referenced keys so that
foreign key checks can be fast and not require a table scan. In the
referencing table, there must be an index where the foreign key
columns are listed as the first columns in the same order. Such an
index is created on the referencing table automatically if it does not
exist. This index might be silently dropped later, if you create
another index that can be used to enforce the foreign key constraint.

Geodjango and Innodb, mixed innodb and myisam models

I keep hearing that InnoDB is better for data integrity, unfortunately as of MySQL 5.6 it has yet to support SPATIAL indexes. A fast SPATIAL index is pretty critical to my app, though what's nice about my model that it's pretty much results in a fairly static (write once, read many) table of (ID, POINT), so I could use MyISAM and not care too much.
I'd like to restrict the use of MyISAM to just that table, and migrate it over when InnoDB support for SPATIAL is ready. Problem is, if I ALTER TABLE after my models are migrated (by having an app/sql/app_model.sql) to switch the table to MyISAM, MySQL complains:
ERROR 1217 (23000): Cannot delete or update a parent row: a foreign key constraint fails
That makes sense, my other models refer to this one and Django automatically makes FOREIGN KEY constraints between those models and this one.
What's the best strategy here? Should I abandon InnoDB and switch everything back to MyISAM? Can I just drop all the FOREIGN KEY constraints?
I tried automating the FOREIGN KEY drops by looking in INFORMATION_SCHEMA.TABLE_CONSTRAINTS, but that only lists the tables that have the constraints, not the tables referred to by those constraints. I would have to do some fuzzy column name matching which feels very brittle.
To solve this I gave up on using InnoDB by default. Because Amazon RDS makes Inno the default, I did this by adding an init_command in my settings.py:
'default': {
'OPTIONS': {
'init_command' : 'SET storage_engine=MYISAM', # Can't make SPATIAL keys on InnoDB
},
}
Then for all but the table with a SPATIAL index I created a $modelname.sql file under the $appname/sql directory that changes the engine after it's created.
-- Alter to InnoDB so we can make concurrent insertions w/o full table lock.
ALTER TABLE <modeltable> ENGINE=INNODB;
Switching to MYISAM default means Django doesn't automatically create the FOREIGN KEY constraints for you for your Inno tables which isn't ideal. I wish there was a way to make Django create them after-the-fact.

What's the safest way to convert table with InnoDB to MyISAM?

My database is currently using the InnoDB engine. Now I want to add the fulltext search feature, which is why I want to convert my tables to MyISAM. But doing so breaks all foreign keys. How can I change my table engines to MyISAM safely?
How can I use SELECT...JOIN after I change my tables to the MyISAM engine?
ALTER TABLE jobs ENGINE = MyISAM;
Cannot delete or update a parent row: a foreign key constraint fails
I'd recommend you to do a dump of the db, change all the text from that file from InnoDB to MyISAM, then load the modified file
As I know, MyISAM doesn't supports foreign keys (compare the features offered by InnoDB vs the features of MyISAM). MySQL tries to tell you that you have to drop every foreign key constraint that references your jobs table before changing its engine to MyISAM.

Copying data over to innodb from myisam

I currently have a database based on a MYISAM storage engine that has a few thousand records. I want to convert my database over to InnoDb storage engine.
It won't be a simple ALTER storage engine command, since I need to add foreign keys to to the current database schema( the current MyISAM db schema does have primary keys though) before I convert it over to InnoDb.
My question is once I convert the DB over to InnoDb would restoring the data from the current MYISAM engine to InnoDb engine would be as simple as firing a PhpMyAdmin instance and back up the data (minus the db schema or structure) and then restore it to the Innodb engine?
What are the potential hurdles in doing this?
Is this the correct way to go about this or what are the various other easier or better ways to restore data?
It won't be a simple ALTER storage engine command, since i need to add foreign keys to to the current database schema
Why not? Sure backup the data first, that is always a good idea, but you don't need to dump and restore the data, you can issue your simple ALTER TABLE, such as:
ALTER TABLE `tablename` ENGINE = InnoDB;
After that you can add any index and foreign key. If any new foreign key fails, you've to fix your data and try again.
When you add foreign keys first, you have to copy your data in a certain order, otherwise your data won't be added because of foreign key constraints.
Therefore, the best thing is checking (through SQL queries) if you can fulfill your foreign key constraints with your current dataset, then copy the data, afterwards, define foreign keys.
But if you export your data from an InnoDB database with PHPMyAdmin, the order is already fulfilled and you can re-import it without any problems.
You could probably add the foreign keys later
Alter the table to use a new engine
Alter each table to use foreign keys
I only see one issue with that and that would be if the foreign keys are broken to start with.