这两个LINQ to SQL查询之间的性能是否有区别?

时间:2018-09-27 08:19:56

标签: c# linq entity-framework-core

我最近一直在研究我的Web应用程序的性能,发现一些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");
}

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

感谢您的任何评论。

编辑:我可能正在EF db上下文上运行查询,因此请忽略该内容。 当前存储库是通用的Abp.Domian.Repository。 GetAll()返回IQueryable

5 个答案:

答案 0 :(得分:3)

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

同时测试它们,对其进行基准测试,查看SQL并使用数据库分析工具进行检查,以防您可能缺少索引或其他优化机会。

仅凭Linq就无法分辨。

答案 1 :(得分:3)

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

.FirstOrDefault()-读取所有列

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

差异将主要基于数据大小和SQL结构,索引及所有。建议通过测试对其进行基准测试

答案 2 :(得分:3)

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

如果GetAll()返回IQueryable<...>,则存在细微差别:

FirstOrDefault()将更改查询中的表达式,这样SQL语句将为Select top 1 ... from

更改表达式后,它将要求Provider的{​​{1}}执行IQqueryable,SQL语句的完整结果将被转移到本地内存中,在这种情况下将是一项。

Expression几乎会执行相同的操作,但SQL将是:Any()

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

因此,如果您只想检查是否有任何元素,则Select top 1Any()更有效率

答案 3 :(得分:2)

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

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

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

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

第一个或默认值:

 str(DT2_mat)
'data.frame':   5120 obs. of  7 variables:
 $ : Factor w/ 2 levels "Archaea","Bacteria": 2 2 2 2 2 2 2 2 2 2 ...
  ..- attr(*, "names")= chr  "P11_16513" "P193_8942" "P187_9526" "P11_4543" ...
 $ : Factor w/ 28 levels "Acidobacteria",..: 2 2 2 2 2 2 2 2 2 2 ...
  ..- attr(*, "names")= chr  "P11_16513" "P193_8942" "P187_9526" "P11_4543" ...
 $ : Factor w/ 60 levels "Acidimicrobiia",..: 3 3 3 3 3 3 3 3 3 3 ...
  ..- attr(*, "names")= chr  "P11_16513" "P193_8942" "P187_9526" "P11_4543" ...
 $ : Factor w/ 108 levels "Acholeplasmatales",..: 29 29 29 29 29 29 29 29 29 29 ...
  ..- attr(*, "names")= chr  "P11_16513" "P193_8942" "P187_9526" "P11_4543" ...
 $ : Factor w/ 216 levels "0319-6A21","0319-6G20",..: 58 58 58 58 58 58 58 58 58 58 ...
  ..- attr(*, "names")= chr  "P11_16513" "P193_8942" "P187_9526" "P11_4543" ...
 $ : Factor w/ 699 levels "Abiotrophia",..: 173 173 173 173 173 173 173 173 173 173 ...
  ..- attr(*, "names")= chr  "P11_16513" "P193_8942" "P187_9526" "P11_4543" ...
 $ : Factor w/ 4964 levels "Abiotrophia defectiva Score:0.87",..: 1613 1529 1449 1448 1565 1438 1563 1532 1623 1605 ...
  ..- attr(*, "names")= chr  "P11_16513" "P193_8942" "P187_9526" "P11_4543" ...
P

任何:

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

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

尝试避免一次在内存中加载数据,那样会给您带来性能上的差异

答案 4 :(得分:1)

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

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

这将确保您的Any在数据库上执行,因为此方法以IQueryable的形式执行Any。

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