【问题标题】:How to speed up loading data using async method in EF?如何在 EF 中使用异步方法加速加载数据?
【发布时间】:2019-05-15 19:18:27
【问题描述】:

到目前为止,我的列表中有很多数据要加载。当我使用普通(同步)方式加载数据时,加载所有数据大约需要 20 秒。我做了这个异步方法,现在我需要大约 7 秒来加载。 我想知道是否有办法加快速度,例如,一打开屏幕就加载前 20 张卡片,然后再加载其他所有内容?到目前为止,这是我的代码..

public async Task<List<CardObject>> GetCardsAsync()
{
    using (var context = new MyCARDEntities())
    {
        return await context.Card
            .Include(f => f.Person)
            .Include(k => k.CardType)
            .Where(arg => arg.LastAction != "D" && arg.PERSON_ID != null)
            .Select(k => new CardObject()
            {
                    Id = k.Id,
                    UID = k.UID,
                    Person = new PersonBasicObject()
                    {
                        Id = k.PersonBasicObject.Id,
                        OIB = k.PersonBasicObject.OIB,
                        Name = k.PersonBasicObject.Name,
                        LastName = k.PersonBasicObject.LastName
                    }
            })
            .ToListAsync();
    }
}

这是在 viewModel 中

private async void LoadCards()
{
    var cards = await repKartica.GetCardsAsync();
    CardLst = new ObservableCollection<CardObject>(cards);
}

private ObservableCollection<CardObject> _CardLst;
public ObservableCollection<CardObject> CardLst 
{
    get => _CardLst;
    set
    {
        _CardLst= value;
        RaisePropertyChanged(() => CardLst);
    }
}

【问题讨论】:

  • 分析您发送到数据库的查询。确定您是否发送低效查询和/或缺少索引。
  • 20 秒和 7 秒都是很长的时间。一种方法是修改你的应用,只返回前 20 张卡片,然后看看需要多长时间。它可能仍然很慢。如果从同步切换到异步会产生很大的不同,您是否会执行多个查询或多次执行相同的查询?有可能优化的方法,但如果有什么让你的应用变慢,最好找到它并直接解决它,而不是试图解决它。

标签: c# .net entity-framework mvvm


【解决方案1】:

使方法异步不会使方法更快,它只是允许方法放弃执行线程以允许其他代码运行。这可以使代码更具响应性,但不会使检索特定数据的速度更快。

首先,如果可以避免,加载大量数据并不是一个好主意。客户是否需要一次查看所有这些数据,还是/是否可以一次将其分页成 20 张卡片的页面?如果是,或者可以分页,那么考虑使用一个分页集合,它可以查询特定的数据页面(使用.Skip().Take())随着可见页面的变化一次只拉回 20 条左右的记录。

接下来是查看正在执行的查询。对您的数据库运行诸如 ExpressProfiler 之类的分析器并捕获 EF 正在运行的 SQL。在企业管理器中执行这些查询的副本以获取执行计划并查看是否有索引建议。

其他提示:使用.Select() 时,不需要使用.Include()。 Select 将生成一个查询以自动从相关实体中提取。

PersonBasicObject 和 CardObject 是您的实体定义吗?如果是这样,这些实体中有多少字段将未被此 Select 填充?理想情况下,您应该使用专用视图模型而不是传递实体。通过使用Select() 填充实体以选择性地填充数据,您正在组合一个不是实体的实体,因为它不是实体的完整表示。由于变量仍然占用内存但未填充,这可能效率低下,并且它具有误导性并导致错误,因为您将拥有需要实体的代码,并且可以被调用/重用但随后处理“真实”完整实体与像这样加载的不完整实体相比。实体的唯一目的应该是表示数据状态,而不是传输视图状态。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-23
    • 1970-01-01
    • 1970-01-01
    • 2019-01-11
    • 2016-10-27
    • 2018-03-07
    • 2016-08-21
    相关资源
    最近更新 更多