枚举关联时,如何改进糟糕的EF4性能



我正在使用Entity Framework 4开发电影数据库应用程序(数据库优先),将大约8200行加载到List需要30秒。涉及到三个表,当我使用.Include()时,性能会下降得更多——加载8200行几乎需要三分钟。这很痛苦。考虑到我同时学习了很多技术,我希望有一个简单的解决方案。以下是详细信息:

表1-视频

这是一个有31列的大表,大约有7800行视频。它使用Guid作为主键。

表2-演员视频(连接表)

该表有两列:(1)VideoID列和(2)ActorID列。这两列都是Guid,分别是Video和Actor表中的外键。此表使用一个组合主键,其中两列都充当主键。EF4没有对此表进行建模;但是,它创建了一个导航属性。该表允许用户为电影分配任意数量的演员。

表3-参与者

有16列,大约400行。同样,主键是Guid。

在代码中,我读取视频表中的大约10列,然后从相关的Actors表中读取列。

C#代码看起来像这样:

var videos = context.Videos
foreach (var video in videos)
{
    // retrieve 10 or so properties from 'video'
    if (video.Actors.Count > 0)
    {
        foreach (var actor in video.Actors)
        {
            // retrieve some properties on the actor
        }
    }
}

我试着在上下文后面添加Include("Actors")。如上所述,视频和表演从可怕到可怕。

我已经查看了使用Include生成的SQL,考虑到视频表中的列数,它大约有2K的文本。

我必须使用主/细节模式拆分视频表吗?我的下一步是缓存actors表,并完全避免导航/关联属性。还有什么其他建议可以加快速度吗?在我看来,它应该在5-6秒内运行。

编辑:数据库为SQL Server CE 3.5。

您要求Entity Framework加载一个视频及其所有参与者,然后在应用程序代码中进行过滤。一般来说,你提取的数据比你需要的要多。我会为你准备SQL Server(或你使用的任何数据库)预过滤器:

var videos = context.Videos;
var results = from video in videos
              where video.Actors.count > 10
              group video.Actors by video.VideoID into grouping
          select new
          {
              video.VideoID,
              video.Actors
          };
foreach (var group in results)
{
    foreach (var actor in group.Actors)
    {
        // do stuff
    }
}

在视频表中加载约8200行及其关联行应该非常快。我在工作中做了一些开发,我必须处理一个7000多万行的测试数据表和一个5表连接。这大概花了半分钟。

但是,它之所以运行得比您所做的快得多,是因为我在SQL Server的内部筛选。使用EF的等效"过程"程序花了几分钟时间,因为我在从数据库中提取行之后进行筛选。

这样想吧:你不仅要求数据库中的每一行,而且多次提取你甚至不需要的数据

尝试使用热切加载:

var videos = context.Videos.Include(v=>v.Actors);
foreach (var video in videos)
{
    foreach (var actor in video.Actors)
    {
    }
}

注意:注意,查询使用延迟执行,这意味着多次迭代也会多次执行查询。如果要多次迭代,请使用.AsEnumerable(),并在迭代前在本地进行分配。此外,分析数据库以查看正在执行的查询将有助于确定还需要急切地获取哪些查询。您可能正在强制EF加载不需要的实体。如果是这种情况,那么您的查询应该只投影(通过使用Select(x=> new {...stuff you need... }))必要的数据。

EDIT:根据Microsoft的说法,Include()不能与投影组合,因此在这种情况下,您需要以不同的方式编写查询。

最新更新