LINQ 性能常见问题解答

     2023-03-31     285

关键词:

【中文标题】LINQ 性能常见问题解答【英文标题】:LINQ performance FAQ 【发布时间】:2010-10-28 15:27:33 【问题描述】:

我正在尝试掌握 LINQ。最困扰我的是,即使我对语法理解得更好,我也不想为了表现力而不知不觉地牺牲性能。

对于“有效的 LINQ”,它们是否是任何好的集中信息库或书籍?如果做不到这一点,您个人最喜欢的高性能 LINQ 技术是什么?

我主要关注 LINQ to Objects,但当然也欢迎所有关于 LINQ to SQL 和 LINQ to XML 的建议。谢谢。

【问题讨论】:

根据我的个人经验,LINQ 的速度与您自己编写的代码的速度完全相同。在许多情况下,由于延迟评估(以及 .NET 团队已经为您完成的疯狂优化),它甚至更快。 我不知道您在什么环境中工作,但我从事对性能至关重要的企业应用程序。每种方法都会定期进行性能审查,并且 LINQ 被严格禁止。使用 LINQ 会受到惩罚,因为必须连续一周每天按需为办公室里的每个人泡茶/咖啡。 @steve 我们在任何情况下都不使用 LINQ。老派的“for”和“foreach”循环是常态 @Rex M - 这次交流正是我问这个问题的原因。我发现很难找到 LINQ 比手动编码循环有所改进的案例,但是当 LINQ 彻底失败时,有很多反例。如果我们无知,请教育我们。 @Rex M - 也许是这样。我只是想知道我在这里看到的性感 LINQ 答案中有多少是最佳的。表现力很诱人。感谢您的想法。 【参考方案1】:

Linq 作为一种内置技术,具有性能优势和劣势。 .NET 团队对扩展方法背后的代码给予了相当多的性能关注,它提供惰性评估的能力意味着对一组对象执行大多数操作的成本分散在需要操作集的更大算法中.但是,您需要了解一些事情,这些事情可能会影响您的代码性能。

首先,Linq 不会神奇地为您的程序节省执行操作所需的时间或内存。它只是可能会延迟这些操作,直到绝对需要。 OrderBy() 执行 QuickSort,这将花费 nlogn 时间,就像您编写自己的 QuickSorter 或在正确的时间使用 List.Sort() 一样。因此,在编写查询时,请始终注意您要求 Linq 对系列执行的操作;如果不需要进行操作,请重新构建查询或方法链以避免它。

出于同样的原因,某些操作(排序、分组、聚合)需要了解它们所作用的整个集合。系列中的最后一个元素可能是操作必须从其迭代器返回的第一个元素。最重要的是,因为 Linq 操作不应该改变它们的源可枚举,但他们使用的许多算法会(即就地排序),这些操作最终不仅会评估,而且会将整个可枚举复制到具体的有限结构中,执行操作,并通过它让步。因此,当您在语句中使用 OrderBy() 并从最终结果中请求一个元素时,给它的 IEnumerable 可以产生的所有内容都会被评估,作为数组存储在内存中,排序,然后返回一个元素时间。道德是,任何需要有限集而不是可枚举的操作都应尽可能放在查询的最后,允许其他操作,如 Where() 和 Select() 以减少源集的基数和内存占用。

最后,Linq 方法极大地增加了系统的调用堆栈大小和内存占用。每个必须知道整个集合的操作都将整个源集合保存在内存中,直到最后一个元素被迭代,并且每个元素的评估将涉及一个调用堆栈,其深度至少是链或子句中方法数量的两倍在您的内联语句中(调用每个迭代器的 MoveNext() 或产生 GetEnumerator,以及沿途对每个 lambda 的至少一个调用)。与执行相同操作的智能设计的内联算法相比,这只会导致更大、更慢的算法。 Linq 的主要优点是代码简单。创建然后排序组值列表的字典不是很容易理解的代码(相信我)。微优化可以进一步混淆它。如果性能是您最关心的问题,那么不要使用 Linq;它将增加大约 10% 的时间开销和几倍于自己就地操作列表的内存开销。然而,可维护性通常是开发人员最关心的问题,而 Linq 肯定会在这方面提供帮助。

关于性能提升:如果您的算法性能是神圣的、不可妥协的首要任务,那么您将使用 C++ 等非托管语言进行编程; .NET 将慢得多,因为它是托管运行时环境,具有 JIT 本机编译、托管内存和额外的系统线程。我会采用“足够好”的哲学; Linq 本质上可能会导致减速,但如果您无法区分,而您的客户也无法区分,那么实际上就没有区别。 “过早优化是万恶之源”;让它发挥作用,然后寻找机会让它更高效,直到你和你的客户同意它足够好。它可能总是“更好”,但除非你想手工打包机器代码,否则你会发现没有一点可以宣布胜利并继续前进。

【讨论】:

“如果性能是您最关心的问题,那么就不要使用 Linq” - Web 开发怎么样?那里的性能可能是一个主要问题,因为您可以预期成千上万的用户同时执行操作,那么您会尝试在 Web 开发中避免使用 Linq 吗? Wellll... 是的,性能是一个问题,但多用户方面的大部分内容是由 ASP.NET 运行时和生命周期的体系结构为您处理的。此外,运行时性能问题通常与构成回发延迟大部分的网络带宽/延迟问题相形见绌。您仍然应该尽可能快地完成服务器端工作,但如果我的网站在实际流量负载下响应不够快,那么结构相对良好的 Linq 查询不会是我的第一个怀疑对象。【参考方案2】:

只需了解 LINQ 在内部执行的操作即可获得足够的信息,以了解您是否受到性能影响。

这是一个简单的例子,其中 LINQ 有助于提高性能。考虑一下这种典型的老式方法:

List<Foo> foos = GetSomeFoos();
List<Foo> filteredFoos = new List<Foo>();
foreach(Foo foo in foos)

    if(foo.SomeProperty == "somevalue")
    
        filteredFoos.Add(foo);
    

myRepeater.DataSource = filteredFoos;
myRepeater.DataBind();

所以上面的代码将迭代两次并分配第二个容器来保存过滤后的值。多么浪费!比较:

var foos = GetSomeFoos();
var filteredFoos = foos.Where(foo => foo.SomeProperty == "somevalue");
myRepeater.DataSource = filteredFoos;
myRepeater.DataBind();

这只迭代一次(当转发器被绑定时);它只使用原始容器; filteredFoos 只是一个中间枚举数。而且,如果出于某种原因,您决定稍后不绑定中继器,则不会浪费任何东西。你甚至不迭代或评估一次。

当您进行非常复杂的序列操作时,您可以潜在地通过利用 LINQ 对链接和惰性求值的固有使用获得很多好处。同样,与任何事情一样,这只是了解它实际在做什么的问题。

【讨论】:

谢谢,这正是我希望看到的一个例子。我只是希望通过示例比试错法或先验分析更容易学习。 +1 表示两次迭代的样本。需要注意的是,过滤后的列表也会消耗内存,这会给 GC 带来一些压力。 我不明白第一个示例如何迭代两次。当您在其上调用 'DataBind()' 时,这是任何 'myRepeater' 的影响吗? @A.R.想想Repeater必须如何在内部工作——它有一个项目模板和一个数据源——它需要遍历源并将每个元素绑定到项目模板的副本。 我不明白为什么 LINQ 实现应该更快。至少在真正枚举中继器的正常情况下不会。检查 LINQ 源代码,您会看到...使用 LINQ,您将节省一次分配,但会执行更多代码(更多方法、更多检查),并且此代码的​​执行效率会降低(与调用者代码混合)。 【参考方案3】:

影响性能的因素有很多。

通常,使用 LINQ 开发解决方案将提供相当合理的性能,因为系统可以构建表达式树来表示查询,而无需在构建时实际运行查询。只有当您迭代结果时,它才会使用此表达式树来生成和运行查询。

就绝对效率而言,针对预定义的存储过程运行您可能会看到一些性能损失,但通常采取的方法是使用提供合理性能的系统(例如 LINQ)开发解决方案,而不必担心百分之几的性能损失。如果查询运行缓慢,那么您可能会考虑优化。

现实情况是,大多数查询通过 LINQ 完成不会有丝毫问题。另一个事实是,如果您的查询运行缓慢,则更有可能是索引、结构等问题,而不是查询本身,因此即使在寻求优化时,您通常也不会触及 LINQ,只是它所针对的数据库结构。

对于处理 XML,如果您将文档加载并解析到内存中(例如基于 DOM 模型的任何内容,或 XmlDocument 或其他任何内容),那么您将获得比执行类似操作的系统更多的内存使用量引发事件以指示查找开始或结束标记,但不构建文档的完整内存版本(如 SAX 或 XmlReader)。缺点是基于事件的处理通常相当复杂。同样,对于大多数文档不会有问题 - 大多数系统都有几 GB 的 RAM,因此占用几 MB 来表示单个 XML 文档不是问题(而且您经常处理大量的 XML 文档,至少在某种程度上依次)。只有当您有一个占用 100 MB 的巨大 XML 文件时,您才会担心具体的选择。

请记住,LINQ 还允许您迭代内存中的列表等,因此在某些情况下(例如,您将在函数中一次又一次地使用一组结果),您可以使用 .ToList 或 .ToArray 返回结果。有时这可能很有用,尽管通常您希望尝试使用数据库的查询而不是内存中的查询。

至于个人最爱 - NHibernate LINQ - 它是一个对象关系映射工具,允许您定义类、定义映射细节,然后让它从您的类而不是反过来生成数据库,以及 LINQ支持非常好(肯定比 SubSonic 之类的要好)。

【讨论】:

【参考方案4】:

在 linq to SQL 中,您不需要太在意性能。您可以以您认为最易读的方式链接您的所有陈述。 Linq 最后只是将所有语句转换为 1 个 SQL 语句,最后才被调用/执行(比如当你调用 .ToList()

如果您想在不同的条件下应用各种额外的语句,var 可以包含此语句而不执行它。只有当您想要将语句转换为对象或对象列表之类的结果时,才会最终执行。

【讨论】:

这仅适用于 LINQ to SQL。 他做到了。见第一次修订的最后一句话。 -1。有时 LinqToSql 会将您的查询转换为 n+1 语句。有时产生的查询不是最优的。 LinqToSql 查询需要数据库性能分析,这与来自任何其他来源的任何其他查询没有什么不同。【参考方案5】:

有一个名为 i4o 的 codeplex 项目,我不久前使用过它,它可以帮助提高 Linq to Objects 的性能,例如在进行相等比较的情况下,例如

from p in People 
where p.Age == 21 
select p;

http://i4o.codeplex.com/ 我没有用 .Net 4 测试过它,所以不能肯定地说它仍然可以工作,但值得一试。 为了让它发挥它的魔力,你通常只需要用一些属性来装饰你的类,以指定应该索引哪个属性。当我之前使用它时,它只适用于相等比较。

【讨论】:

我发现,一般来说,如果我使用 LINQ 做一些需要索引来加速它的事情,通常最好自己做索引,因为 a) 我可能希望它们用于其他目的,并且 b ) 我控制索引的管理方式。这也让我可以创建更复杂的索引

LINQ Any vs Exists 性能 [重复]

】LINQAnyvsExists性能[重复]【英文标题】:LINQAnyvsExistsPerformance[duplicate]【发布时间】:2011-10-0511:42:57【问题描述】:可能重复:Linq.AnyVS.Exists-Whatsthedifference?在LINQ查询中使用any与存在之间是否存在性能差异?特别是LINQtoEntities。【... 查看详情

使用联接将 LINQ 查询转换为 SQL 查询以获得更好的性能

】使用联接将LINQ查询转换为SQL查询以获得更好的性能【英文标题】:ConvertLINQquerytoSQLqueryforbetterperformancebyusingjoins【发布时间】:2020-03-1417:16:44【问题描述】:我想提高我的查询性能。当您查看我之前的问题时,您会看到我的问... 查看详情

计算数组的非空元素 - LINQ 性能问题 [重复]

】计算数组的非空元素-LINQ性能问题[重复]【英文标题】:Countingnotnullelementsofarray-LINQperformanceissue[duplicate]【发布时间】:2021-09-2620:39:28【问题描述】:我需要一种快速而肮脏的方法来计算数组,但只选择元素是否包含值。经过一... 查看详情

提高 LINQ 查询性能?

】提高LINQ查询性能?【英文标题】:ImproveLINQqueryperformance?【发布时间】:2013-10-1807:47:19【问题描述】:publicList<Agents_main_view_distinct>getActiveAgents(DateTimestart,DateTimeend)myactiveagents=null;myactiveagents=mydb.Agents_main_view 查看详情

解释不同 LINQ 语句之间的性能差异

】解释不同LINQ语句之间的性能差异【英文标题】:ExplainperformancedifferencesbetweendifferentLINQstatements【发布时间】:2021-09-2418:47:53【问题描述】:我正试图解决以下问题:我正在尝试优化这个查询:(fromurinUserRateswhereur.BillingProperty==nu... 查看详情

Linq 性能和延迟执行

】Linq性能和延迟执行【英文标题】:Linqperformanceanddelayedexecution【发布时间】:2011-06-1222:00:45【问题描述】:我已经为.NetCF运行了一些测试。基本上,我想比较for、foreach、扩展方法ForEach和LINQ查询。这是整个代码(你可以跳过它... 查看详情

C# Linq To SQL 插入单个大行性能问题

】C#LinqToSQL插入单个大行性能问题【英文标题】:C#LinqToSQLinsertasinglebigrowperformanceissue【发布时间】:2022-01-0823:49:30【问题描述】:我有一个程序使用旧的LinqToSQL将ASP.NET应用程序连接到SQLServerDB。ASP.NET应用程序和SQLServer实例位于... 查看详情

LINQ to SQL / LINQ to Collections 性能

】LINQtoSQL/LINQtoCollections性能【英文标题】:LINQtoSQL/LINQtoCollectionsPerformance【发布时间】:2010-07-3022:18:22【问题描述】:有两个选项可用于处理填充了SQL的LINQtoCollections(我使用的是Oracle提供程序,因此没有ORM就没有LINQ)。执行一... 查看详情

LINQ2SQL 事务的性能

】LINQ2SQL事务的性能【英文标题】:LINQ2SQLperformancewithtransactions【发布时间】:2009-05-1304:04:44【问题描述】:我遇到了LINQ2SQL和事务的主要性能问题。我的代码使用IDE生成的LINQ2SQL代码执行以下操作:运行存储过程检查现有记录如... 查看详情

LINQ 包括在搜索时降低性能

】LINQ包括在搜索时降低性能【英文标题】:LINQIncludeslowingdownperformancewhensearching【发布时间】:2018-11-0904:13:21【问题描述】:我们有以下方法允许我们在项目表中搜索DataGrid:publicasyncTask<IEnumerable<Project>>GetFilteredProjects(st... 查看详情

除了官方常见问题解答中列出的问题外,在 Windows 服务器上用于生产的 XAMPP 是不是还有其他安全/性能问题?

】除了官方常见问题解答中列出的问题外,在Windows服务器上用于生产的XAMPP是不是还有其他安全/性能问题?【英文标题】:Isthereanyothersecurity/performanceissueofXAMPPforproductiononwindowsserverexceptthoselistedinofficialFAQ?除了官方常见问题解答... 查看详情

linq to sql startwith 性能索引列

】linqtosqlstartwith性能索引列【英文标题】:linqtosqlstartwithperformanceindexedcolumns【发布时间】:2014-11-1321:18:53【问题描述】:我首先使用实体​​代码。索引列:SourceCatalogId已禁用类别路径表格中有40000行,我的问题是查询需要40秒... 查看详情

Entity Framework 4 中的 Linq 查询。糟糕的性能

】EntityFramework4中的Linq查询。糟糕的性能【英文标题】:LinqqueriesinEntityFramework4.Horribleperformance【发布时间】:2011-04-1509:30:44【问题描述】:在我的项目中,我使用EntityFramework4来处理数据。我通过一个简单的查询发现了可怕的性... 查看详情

Linq to Entities 与 ESQL 的性能对比

】LinqtoEntities与ESQL的性能对比【英文标题】:PerformanceofLinqtoEntitiesvsESQL【发布时间】:2010-09-0712:11:48【问题描述】:使用实体框架时,ESQL的性能是否优于LinqtoEntities?我更喜欢使用LinqtoEntities(主要是因为强类型检查),但我的... 查看详情

LINQ 查询子句的顺序是不是会影响实体框架的性能?

】LINQ查询子句的顺序是不是会影响实体框架的性能?【英文标题】:ShouldtheorderofLINQqueryclausesaffectEntityFrameworkperformance?LINQ查询子句的顺序是否会影响实体框架的性能?【发布时间】:2013-06-2614:55:08【问题描述】:我正在使用实... 查看详情

在 LINQ 中使用组时如何提高性能

】在LINQ中使用组时如何提高性能【英文标题】:HowtoincreatetheperformancewhenusinggroupinLINQ【发布时间】:2021-11-0110:02:06【问题描述】:数据库Cars|CarDetails|Owners----------------------------------Id|CarDetailId|IdName|CarId|CarIdType|CarId|OwnerName||Pho 查看详情

Linq:高性能数据库查询仅查询每个第 n 个元素

】Linq:高性能数据库查询仅查询每个第n个元素【英文标题】:Linq:Performantdatabasequeryonlyqueryingeverynthelement【发布时间】:2019-12-0817:07:09【问题描述】:我正在从事一个个人项目,在该项目中我需要一些关于对数据库进行高性能Lin... 查看详情

使用 TPH 和复杂类型时 LINQ to Entities 的初始性能问题,Pregen 视图似乎啥都不做?

】使用TPH和复杂类型时LINQtoEntities的初始性能问题,Pregen视图似乎啥都不做?【英文标题】:InitialperformanceissuewithLINQtoEntitieswhenusingTPH&complextypes,PregenViewsseemtodonothing?使用TPH和复杂类型时LINQtoEntities的初始性能问题,Pregen视图似... 查看详情