我正在使用Entity Framework 4(数据库优先)处理电影数据库应用程序,并且需要30秒才能将大约8,200行加载到List中。涉及到三个表,当我使用.Include()时,性能会降低甚至更多 - 加载8,200行几乎需要三分钟。这很痛苦。鉴于我正在学习很多技术,我希望有一个简单的解决方案。以下是详细信息:
表1 - 视频
这是一张包含31列大约7,800行视频的大表。它使用Guid作为主键。
表2 - ActorsVideos(联结表)
此表有两列:(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。
答案 0 :(得分:3)
你要求Entity Framework加载一个视频及其所有的actor,然后你在应用程序代码中进行过滤。通常,您提供的数据超出了您的需求。我会让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行及其在视频表中的相关行应该非常快。我在我的工作中做了一些开发,我不得不处理一个带有5个表连接的7000多万行测试数据表。这发生在半分钟左右。
但是,它运行速度比你正在进行的速度快得多的原因是因为我正在过滤 SQL Server中的。使用EF的等效“程序”程序花了几分钟,因为我在从数据库中提取行后进行了过滤。
以这种方式思考:您不仅要求数据库中的每一行,而且还要提取您甚至不需要多次的数据。
答案 1 :(得分:0)
尝试使用eager loading:
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... })
)必要的数据。
编辑:根据Microsoft,Include()
无法与投影合并,因此在这种情况下,您需要以不同方式编写查询。