C# LINQ Any vs FirstOrDefault的性能!=无效的
在我贡献的开源项目(OSP)代码中有多个地方,必须确定集合中的元素是否满足特定条件 我见过在某些情况下使用LINQ表达式C# LINQ Any vs FirstOrDefault的性能!=无效的,c#,linq,C#,Linq,在我贡献的开源项目(OSP)代码中有多个地方,必须确定集合中的元素是否满足特定条件 我见过在某些情况下使用LINQ表达式Any(lambda表达式)和FirstOrDefault(lambda表达式)!=空,但从未考虑过 我现在已经到了一个地步,我必须对从查询到数据库的集合进行一些迭代,并希望优化运行时 所以我认为FirstOrDefault(lambda表达式)!=null应该比任何(lambda表达式)快,对吗 对于FirstOrDefault(lambda表达式)!=null,迭代(可能)
Any(lambda表达式)
和FirstOrDefault(lambda表达式)!=空
,但从未考虑过
我现在已经到了一个地步,我必须对从查询到数据库的集合进行一些迭代,并希望优化运行时
所以我认为FirstOrDefault(lambda表达式)!=null应该比任何(lambda表达式)
快,对吗
对于FirstOrDefault(lambda表达式)!=null
,迭代(可能)在找到满足条件的元素时停止(更糟糕的情况是,它迭代整个集合并返回null
)
在Any(lambda表达式)
的情况下,我认为迭代将继续到集合的末尾,即使找到了满足条件的元素
编辑:杰克逊·波普(Jackson Pope)提到并链接了MSDN的相关文章,但上述说法并不正确
我的想法是正确的还是遗漏了什么?在Any()
中的枚举也会在找到匹配项时停止:
我希望表现会非常相似。请注意,FirstOrDefault
版本不会与值类型集合一起工作(因为默认值不是null),但是Any
版本会。在找到满足条件的元素后,为什么Any应该继续?如果该条件适用于1个元素,则该条件限定为“任意”
我认为它们的性能应该差不多,但任何()都可以更清楚地表达您的意图 你在这里混东西。您谈论的是集合,但您似乎没有使用LINQ访问对象,而是查询数据库
LINQ到对象:
并且应该执行相同的操作,因为它们的代码几乎相同:
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;
LINQ到某个数据库:
您正在使用实体框架、LINQ to SQL或NHibernate,并在相应的数据上下文上使用and。
在这种情况下,实际上没有集合,因为这些调用不是在内存中的对象上执行的,而是转换为SQL
这意味着,性能差异源于LINQ提供程序如何将代码转换为SQL,因此最好先检查创建的语句。它们相等吗?或者它们是非常不同的(从X中选择计数(0)还是从X中选择前1)?那么差异可能在于数据库的查询优化器、索引以及其他方面。这个问题的问题在于它没有在上下文中被询问。
我提供了一个答案,因为我在代码评审中经常看到这一点,这让我感到困扰。
LINQ不应该成为停止思考的借口
var people = new [] { "Steve", "Joe" };
if (people.Any(s => s == "Joe"))
{
var joe = people.First(s => s == "Joe");
// do something with joe
}
// if people is 1,000,000 people and joe is near the end do we want BigO to approach 2N here at worst case ?
var joe1N = people.FirstOrDefault(s => s == "Joe");
if (joe1N != null)
{
// do something with joe
}
// or do we want to ensure worst case is N by simply using a variable ?
我的两分钱
我在使用Any()时遇到了严重的性能问题。我使用Telerik网格显示相关数据的列表,即
-我有一张“人”的桌子
-“公司”的桌子
-“人民公司”链接表
-“人员控制”链接表
-以及一个“ROL”表,其中包含主类别、子类别和描述
该视图混合了数据,并具有一些属性,可根据需要加载有关特定角色(管理员、报告员、经理)的数据
我的网格使用AJAX,使用“Any”加载需要10秒以上,使用“FirstOrDefault”加载需要3秒或更少。没有花时间调试它,因为需要拦截来自telerik组件和我的模型的调用
希望这有助于。。。所以好好测试一下:)我们可以使用.Count(x=>x…)!=0而不是使用.Any(x=>x…)或.FirstOrDefault(x=>x…)!=空
(@p__linq__0 varchar(8000))SELECT TOP (1)
[Extent1].[Col_1] AS [Col_1],
[Extent1].[Col_2] AS [Col_2],
...
[Extent1].[Col_n] AS [Col_n]
FROM [dbo].[Table_X] AS [Extent1]
WHERE [Extent1].[Col_1] = @p__linq__0
因为Linq的查询生成如下所示
(在Any()中,我认为第二个(不存在)条件是不需要。)
.Any(x=>x.Col\u 1=='xxx')
.FirstOrDefault(x=>x.Col_1=='xxx')!=空
(@p__linq__0 varchar(8000))SELECT TOP (1)
[Extent1].[Col_1] AS [Col_1],
[Extent1].[Col_2] AS [Col_2],
...
[Extent1].[Col_n] AS [Col_n]
FROM [dbo].[Table_X] AS [Extent1]
WHERE [Extent1].[Col_1] = @p__linq__0
.Count(x=>x.Col\u 1=='xxx')!=0
(@p__linq__0 varchar(8000))SELECT
[GroupBy1].[A1] AS [C1]
FROM ( SELECT
COUNT(1) AS [A1]
FROM [dbo].[Table_X] AS [Extent1]
WHERE [Extent1].[Col_1] = @p__linq__0
) AS [GroupBy1]
尽管它有类似的实现,但我认为Any的速度要快一点,因为它不必返回对象,在某些情况下,对象的状态和行为可能很丰富,这取决于查询的考虑程度。因此,当您想知道是否存在满足指定条件的对象时,是否使用Any()
,但是FirstorDefault()
如果你真的想要那个对象回来?@Chris:是的,我就是这么用的。那为什么FirstorDefault(lambda表达式)!=空
更快?完成了一些Ticks
测试和FirstOrDefault(lambda表达式)!=null
总是结束得更快。@Jimi您必须向我们展示您的测试代码。很难做到正确。@AakashM它涉及到对数据库的查询,因此即使发布代码,您也无法对其进行测试。“在Any(lambda表达式)
的情况下,即使找到了满足条件的元素,我想迭代仍会继续到集合的末尾”。为什么?因为我没有读杰克逊·波普提到的MSDN文章。lolnor没有——我只是没有理由认为LINQ实现是荒谬的。我的问题不是表达意图和代码可读性,而是运行时性能。Any()更干净,但FirstOrDefault()通常会尝试返回找到的第一个项目,因此从技术上讲,它会占用带宽和不需要的返回数据。实际上,LINQ中的优化可能会阻止这种情况的发生,但您想依赖于它吗?这里有一个要点。我们使用实体进行数据库查询,并将表存储在集合中。然后我们迭代这些集合,用LINQ提取我们想要的数据。@Jimi:我不理解你的co
(@p__linq__0 varchar(8000))SELECT
[GroupBy1].[A1] AS [C1]
FROM ( SELECT
COUNT(1) AS [A1]
FROM [dbo].[Table_X] AS [Extent1]
WHERE [Extent1].[Col_1] = @p__linq__0
) AS [GroupBy1]