Isr*_*eca 2 mysql sql indexing foreign-keys database-indexes
在MySQL 5.6.34中是否可以有没有索引的外键?我想要那是因为我在2000万行中用另一个表的外键创建了一个可为空的列。由于这是一项新功能,因此只有新行的该列可能会填充实际值,并且您可能会期望该索引的基数变得可怕。因此,在大多数情况下,使用该索引实际上不是一个好主意。问题:我有很多查询都具有相同的限制:
[...] from large_table where tenant_id = ? and nullable_foreign_key_with_index is null and [...]
Run Code Online (Sandbox Code Playgroud)
问题?MySQL认为使用index_merge / intersect策略进行查询解析是一个好主意。在这种情况下的MySQL会做2个查询并行:一个tenant_id(使用一个有效和良好的指数)和另一个nullable_foreign_key_with_index是坏的,几乎是给定的“全表并行扫描”,这个指数的基数是<1000中有超过2000万行的表格。有关此“问题”的更多详细信息,请参见此处
那么,什么是可行的解决方案?鉴于MySQL“强制”外键附加了索引:
删除外键和索引。这很糟糕,因为在应用程序出现错误的情况下,我们可能会损害参照完整性。
FOREIGN_KEY_CHECKS = 0; 跌落指数;FOREIGN_KEY_CHECKS = 1。这很不好,因为即使外键仍然存在,MySQL也不再验证该列以检查该值是否实际存在。那是个错误吗?
在所有现有查询中使用查询提示,以确保我们仅使用旧的高效“ tenant_id_index”。这很糟糕,因为我必须查找所有现有查询,并且还记得在构建新闻查询时再次使用它。
因此,我怎么说:“ MySQL,不必为这个外键创建索引,而是继续验证相关表中的内容,该表无论如何都由主键索引”。我想念什么吗?到目前为止,最好的主意是删除外键,仅相信该应用程序可以按预期运行(可能确实如此),但这将引发关于在APP与DATABASE中具有约束的经典讨论。有任何想法吗?
对于此查询:
from large_table
where tenant_id = ? and
nullable_foreign_key_with_index is null and [...]
Run Code Online (Sandbox Code Playgroud)
只需添加索引large_table(tenant_id, nullable_foreign_key_with_index)。
MySQL应该在表中使用该索引。
我很确定您可以向后进行此操作(我将100%确定比较是否为以外的任何其他方法NULL,但我很确定MySQL NULL也会做正确的事情。)
large_table(nullable_foreign_key_with_index, tenant_id)
Run Code Online (Sandbox Code Playgroud)
MySQL将认识到该索引适用于外键,而不创建任何其他索引。