实体框架中的一对一外键带来了巨大的性能打击



我要让它变得非常简单。我有两张桌子。

public class User
{
    public virtual int UserId { get; set; } //primary key AND foreign key
    //user attributes in here
    public virtual UserProfile UserProfile { get; set; }
}
public class UserProfile
{
    public virtual int UserId { get; set; } //primary key AND foreign key
    //profile attributes in here
    public virtual User User { get; set; }
}

基本上,它们是在1-1关系中共享主键的两个表。我不知道这些是否应该合并为一个,我是基于现有的数据库。

现在,我的问题是当我访问它。

此代码运行速度很快(第二个,可能是两个):

List<User> userList; //**This userList is defined elsewhere, but it's a list of about 400 users.
foreach (User user in userList)
{
    var test = user.FirstName;
}

此代码运行速度非常慢(10-30秒):

List<User> userList; //**This userList is defined elsewhere, but it's a list of about 400 users.
foreach (User user in userList)
{
    var test = user.UserProfile.EmailAddress;
}

当我从用户表访问UserProfile时,为什么我的代码要花这么长时间?!

可能是因为您在此处延迟加载UserProfile。这意味着,对于循环中的每个迭代,当您尝试访问电子邮件地址时,您都会单独调用DB以加载UserProfile

我不确定您是如何创建userList集合的,但假设您对User表进行简单查询,则可以使用Include来预先加载您想要的任何属性:

var userList = (from u in dbContext.Users.Include("UserProfile")
                select u)

现在,性能打击仅限于最初执行此查询时,对结果进行枚举将不再需要对DB进行单独调用。

如果没有问题中的User,很难确定,但这就是我所看到的;

第一个查询循环遍历所有User对象,并打印每个对象的FirstName
1个SQL查询

第二个查询在所有User对象中循环,并为每个对象向数据库发送一个查询,以获取访问EmailAddress的UserProfile
401个查询

你应该仔细阅读懒惰加载和急切加载的对比。

最新更新