如何阻止EF Core索引所有外键

时间:2018-03-22 15:11:40

标签: entity-framework ef-core-2.0

Entity Framework Indexing ALL foreign key columns之类的问题所述,EF Core似乎会自动为每个外键生成一个索引。这对我来说是一个合理的默认设置(让我们不要在这里发表意见之战......),但有些情况下,它只是浪费空间并减慢插入和更新速度。如何根据具体情况对其进行预防?

我不想完全把它关掉,因为它比伤害更有益;我不想为我想要的所有索引手动配置它。我只想在特定的 FK上阻止它。

相关的问题:这些索引是在EF文档中的任何地方自动创建的吗?我无法在任何地方找到它,这可能就是为什么我无法找到如何禁用它?

有人肯定会质疑我为什么要这样做...所以为了节省时间,链接问题的OPer在评论中给出了一个很好的例子:

  

例如,我们有一个People表和一个Addresses表。该   People.AddressID FK被EF索引,但我只是从一个开始   People行并搜索Addresses记录;我找不到了   Addresses行,然后在People.AddressID列中搜索   匹配记录。

3 个答案:

答案 0 :(得分:2)

EF Core具有配置选项来替换其服务之一。

我发现将IConventionSetBuilder替换为自定义项是一种更清洁的方法。

https://giridharprakash.me/2020/02/12/entity-framework-core-override-conventions/

答案 1 :(得分:1)

如果真的有必要避免使用一些外键索引 - 据我所知(目前) - 在.Net Core中,有必要删除将在生成的迁移代码文件中设置索引的代码。 / p>

另一种方法是将一个自定义迁移生成器与一个属性结合使用,或者可能是一个避免索引创建的扩展方法。您可以在EF6的这个答案中找到更多信息:EF6 preventing not to create Index on Foreign Key。但我不确定它是否也适用于.Net Core。这种方法似乎有点不同,这里有一个MS doc article应该有所帮助。

但是,我强烈建议不要这样做!我反对这样做,因为你必须修改生成的迁移文件,而不是因为没有使用FK的索引。就像你在问题评论中提到的那样,在现实场景中,有些案例需要采用这种方法。

对于其他人,他们不确定是否必须避免在FK上使用索引,因此他们必须修改迁移文件:

在你走这条路之前,我建议用FK上的索引实现应用程序,并检查性能和空间使用情况。因此我会产生大量的测试数据。 如果它确实导致测试或QA阶段的性能和空间使用问题,那么仍然可以删除迁移文件中的索引。

因为我们已在此处与EnsureCreated vs migrations聊天,以获取有关EnsureCreated和迁移的完整信息(即使您不需要它: - )):< / p>

答案 2 :(得分:0)

Entity Framework core 2.0(问问题时可用的最新版本)没有这种机制,但是EF Core 2.2可能是Owned Entity Types形式。

就是说,因为您说过:

”我只会从People行开始搜索Addresses记录;我永远不会找到Addresses行”

然后,您可能希望将Address设置为拥有的实体类型(尤其是'Storing owned types in separate tables'的变体),以匹配将地址信息存储在单独位置中的选择Addresses表)。 该功能的文档似乎说一个匹配项:

“拥有的实体实质上是所有者的一部分,没有它就无法存在”

顺便说一句,既然EF中的功能,这可以证明EF为什么总是为HasMany / HasOne创建索引。可能是因为Has*关系旨在用于其他实体(与“值对象”相对),并且这些实体由于具有自己的标识,因此必须独立查询 并允许使用导航属性访问与它们相关的其他实体。对于这样的用例,使用没有索引的导航属性绝对是危险的(一些查询可能会使数据库速度大大降低)。

这里有一些警告:

将实体转换为拥有的实体并不仅会指示EF有关索引,而且还会指示以某种不同的方式将模型映射到数据库(在下面进行更多说明),但最终结果是实际上没有People上的额外索引。

但是有可能,这实际上可能是为您提供的更好解决方案:这样一来,您还说没有人可以查询地址(通过not allowing to create a DbSet<T> of that type),从而最大程度地减少了有人通过这些昂贵的无索引查询将其用于其他实体。

关于区别是什么,您会注意到,如果将AddressPerson所有,则EF将在PersonId表中创建Address列,它与AddressId表中的People不同(从某种意义上说,缺少外键有点作弊:那里有一个用于从Address查询Person的索引,只是因为它是People表的主键索引(始终存在)。但是请注意,这种设计实际上是相当好的-它不仅需要少一列(AddressId中不需要People),而且还可以保证没有办法制作孤立的Address记录您的代码将永远无法访问。

如果您仍然希望将AddressId列保留在Addresses中,那么仍然有一个选择:

  • 只需为AddressId表中的外键选择名称Addresses,然后“假装”您不知道它的值与PersonId相同:)

如果该选项不好笑(例如,因为您无法更改数据库架构),那么您就有些运气了。但请注意,在Current shortcomings of EF中,它们仍然列出“拥有的实体类型的实例不能由多个所有者共享” ,而先前版本的一些缺点已在此处列出,并已解决。在我看来,可能值得关注该空间,因为解决该空间可能涉及引入将AddressId放入People的功能,因为在这样的模型中,要使拥有的对象成为在许多实体之间共享时,必须将外键与所属实体放在一起,以为每个实体创建一个具有相同值的关联。