Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MySQL: Create a Foreign key without an Index

Is it possible to have a foreign key without an index in MySQL 5.6.34? I want that because I created a nullable column in 20M rows with a foreign key to another table. As this is a new feature, only the new rows MAY have this column filled with an actual value, and as you may expect, the cardinality of that index becomes horrible. So, for most of the time, using that index is actually a bad idea. The problem: I have tons of queries that shares this same restriction:

[...] from large_table where tenant_id = ? and nullable_foreign_key_with_index is null and [...]

The issue? MySQL thinks that it's a good idea to use an index_merge/intersect strategy for query resolution. In this case MySQL would do 2 queries in parallel: one with tenant_id (which uses a valid and good index) and another one with nullable_foreign_key_with_index which is bad, almost a "full table scan in parallel" given that the cardinality of this index is <1000 in a table with >20M rows. More details about this "problem" in here

So, what are the pssible solutions? Given that MySQL "forces" a foreign key to have an index attached:

  1. Drop the foreign key and the index. This is bad, because in the case of a bug in the app we may compromise the referential integrity.

  2. FOREIGN_KEY_CHECKS=0; Drop index; FOREIGN_KEY_CHECKS=1. This is bad, because even that the foreign key still exists, MySQL doesn't validade the column anymore to check if the value actually exists. Is that a bug?

  3. Use query hints in all existing queries to make sure that we are only using the old and efficient "tenant_id_index". This is bad because I have to hunt down all existing queries and also remember to use it again when news queries are built.

So, how can I say: "MySQL, don't bother creating an index for this foreign key, but keep validating it's content in the related table, which is indexed by primary key anyway". Am I missing something? The best idea so far is to remove the foreign key and just believe that the app is working as expected, which probably it is, but this would start a classic discussion about having constraints in APP vs DATABASE. Any ideas?

like image 208
Israel Fonseca Avatar asked Dec 23 '22 07:12

Israel Fonseca


1 Answers

For this query:

from large_table
where tenant_id = ? and
      nullable_foreign_key_with_index is null and [...]

Just add the index large_table(tenant_id, nullable_foreign_key_with_index).

MySQL should use this index for the table.

I'm pretty sure you can do this backwards (I would be 100% sure if the comparison were to anything other than NULL, but I'm pretty sure MySQL does the right thing with NULL as well.)

large_table(nullable_foreign_key_with_index, tenant_id)

And MySQL will recognize that this index works for the foreign key and not create any other index.

like image 169
Gordon Linoff Avatar answered Jan 03 '23 02:01

Gordon Linoff