【问题标题】:Is there any difference in performance between these two LINQ to SQL queries? [duplicate]这两个 LINQ to SQL 查询之间的性能有什么不同吗? [复制]
【发布时间】:2018-09-27 21:09:44
【问题描述】:

我最近一直在研究我的网络应用程序性能,发现了一些 LINQ 查询,我不确定更改它们是否会提高性能。

目前的代码基本上是这样的:

var result = _carsRepository.GetAll()
                 .Where(x => x.Name == input.Name)
                 .FirstOrDefault();
if (result != null)
{
    throw new Exception("test");
}

我正在考虑将其更改为:

    var result = _carsRepository.GetAll()
                     .Where(x => x.Name == input.Name)
                     .Any();
if (result)
{
    throw new Exception("test");
}

在我的理解中,第一个查询将返回一个实际的实体,我不需要它,因为我只想知道同名的记录是否已经存在于数据库中。第二个查询只返回一个布尔值。

我会感谢任何 cmets。

编辑:我可以在 EF db 上下文中运行查询,所以请忽略它。 当前存储库是一个通用的 Abp.Domian.Repository。 GetAll() 返回 IQueryable

【问题讨论】:

  • 一般经验法则:测试两者,获得基准。避免过早的优化,仅当这已被确定为应用程序的性能瓶颈时才关心。
  • 您可能会从数据库中提取 100000000 条记录,然后再执行 where,如果没有,您可能需要索引 Name
  • @Saruman: index or not on Name 与此问题无关,因为 Where 在两个查询中完全相同。
  • @TimSchmelter 你是对的,但我只是在猜测,在我继续下一个问题之前
  • 除非明确确定为瓶颈(通过测量),否则性能很少是更改代码的好理由。在这种情况下更改代码的更好理由是使用.Any() 的版本更清楚地表达了您正在做的事情的意图。

标签: c# linq entity-framework-core


【解决方案1】:

我不确定GetAll() 做了什么。如果它将所有项目从您的数据库移动到您的本地内存,那么我不会打扰:尝试改进该语句。如果您只需要第一个,为什么要获取所有项目。

如果GetAll() 返回一个IQueryable<...>,那么会有细微的差别:

FirstOrDefault() 将更改查询中的表达式,使得 SQL 语句将是 Select top 1 ... from

修改表达式后会要求IQqueryable中的Provider执行Expression,SQL语句的完整结果会被转移到本地内存中,本例中为一项。

Any() 几乎会做同样的事情,除了 SQL 将是:Select top 1 1 from ...

很容易看出Select top 1 1 最多传输一个整数,而Select top 1 将传输所有选定的列。

因此,如果您只想检查是否有任何元素,Any()FirstOrDefault 更有效

【讨论】:

    【解决方案2】:

    我们无法告诉您,因为我们既不知道您的存储库类做了什么,也不知道您的数据库驱动程序如何处理到 SQL 的转换。

    测试两者,对它们进行基准测试,查看 SQL 并使用您的数据库分析工具检查您是否可能错过了索引或其他优化机会。

    仅从 Linq 无法判断。

    【讨论】:

    • 这真的是答案吗?听起来像是对我的评论。问题是 - 正如您正确指出的那样 - 无法回答。
    • @HimBromBeere 在我看来,告诉某人为什么它不能完成可能是一个答案,特别是如果它包含前进的替代步骤。但请随时让审阅者决定。
    • 我应该在我的问题中提供更多细节。我的问题很笼统,我可以在 EF db 上下文中执行 LINQ。我只是想知道差异有多大。
    【解决方案3】:

    可能会有细微的差别,因为

    .FirstOrDefault() - 读取所有列

    .Any() - 只需检查是否有条目

    差异主要取决于数据大小和 SQL 结构、索引等。建议通过测试对它们进行基准测试

    【讨论】:

    • 所以你是说如果表包含数百列,差异会很大?
    • 这取决于表的列和数据。例如与 VARCHAR(20) 相比,VARCHAR(MAX) 列需要大量时间。还有很多其他因素。我只是回答 First() 和 Any() 的区别
    【解决方案4】:

    没有。您可能不会获得任何性能差异。因为

    1) Any() 将在找到匹配项后立即返回。

    2) FirstOrDefault() 迭代(可能)在找到满足条件的元素时停止。

    LINQ to 对象: Enumerable.AnyEnumerable.FirstOrDefault 应该执行相同的操作,因为它们的代码几乎相同:

    FirstOrDefault:

    foreach (TSource source1 in source)
    {
        if (predicate(source1))
            return source1;
    }
    return default (TSource);
    

    任何:

    foreach (TSource source1 in source)
    {
        if (predicate(source1))
            return true
    }
    return false;
    

    现在。看起来您正在从内存中的数据库中获取所有记录,然后应用 where 子句。

    尽量避免在内存中一次加载数据。那么它会给你带来性能差异

    【讨论】:

    • 如果其中一列是 10mb 字节数组怎么办
    • 在这种情况下也可以相同
    • 问题不在于 linq2objects。因此,在 FirstOrDefault 的情况下,将生成 select top 1 *,在 10mb 字节数组的情况下,作为将被提取的列之一。对于Any(),它不会。
    【解决方案5】:

    如前所述,尚不清楚您的存储库的作用。但是,如果您遵循 RepositoryPattern,则应考虑将 Any 作为方法添加到您的存储库中。

    public virtual bool Any(Expression<Func<T, bool>> predicate)
    {
        return _context.Set<T>().Any(predicate);
    }
    

    这将确保您的 Any 在数据库上执行,因为此方法将 Any on/ 作为 IQueryable 执行。

    如果您不在存储库中使用泛型,则将 T 替换为您的目标类。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-05-16
      • 2014-02-08
      • 1970-01-01
      • 1970-01-01
      • 2012-02-18
      • 2012-08-05
      • 1970-01-01
      相关资源
      最近更新 更多