一尘不染

实体框架索引所有外键列

sql

这可能是太多基于意见的问题,但这里有:

我发现了与实体框架和数据库迁移有关的一个有趣的怪癖。看来,每当我们创建外键时,它也会在该列上创建索引。

我读了一个SO问题:实体框架代码第一个外键添加索引,每个人似乎都说这是一个很好的,有效的主意,但我不知道怎么做。索引列是非常特定于环境的。例如,EF索引了我的表上几乎从来没有(〜1%)用于搜索的FK,并且也索引了源表,这意味着即使我加入其他表,我也使用它的PK搜索FK的链接表…在那种情况下(我知道)对FK进行索引并没有任何好处。

我的问题:

我想念什么吗?有什么原因为什么我想索引一个FK列,该列从不被搜索并且在任何联接中始终位于源表上?

我的计划是删除一些可疑的索引,但我想确认没有缺少一些优化概念。


阅读 156

收藏
2021-03-10

共1个答案

一尘不染

在EF CodeFirst中,建模外键关系的一般原因是为了实体之间的可导航性。考虑一个Country和的简单情况,City为以下LINQ语句定义了急切的加载:

var someQuery = 
   db.Countries
     .Include(co => co.City)
     .Where(co => co.Name == "Japan")
     .Select(...);

这将导致以下查询:

SELECT *
FROM Country co
INNER JOIN City ci
  ON ci.CountryId = co.ID
WHERE co.Name = 'Japan';

如果没有在外键上启用索引City.CountryId,则SQL将需要扫描“城市”表,以便在JOIN期间为“国家/地区”过滤城市。

TL; DR

建议使用外键索引,即使您不直接在外键上进行过滤,联接中仍将需要它。似乎有一些例外:

  • 如果外键的选择性非常低,例如在上述情况下,如果国家表中所有城市的50%在日本,则该索引将无用。

  • 如果您实际上从未浏览过该关系。

另外一个优化考虑因素是是否Clustered Index在子表的“表”中使用外键(即按国家对城市进行集群)。这在parent:child表关系中通常是有利的,在该关系中,通常可以同时检索父级的所有子行。

2021-03-10