我只是考虑当我在LINQ查询中同时使用OrderBy()
和Distinct()
时,哪个为我提供了最佳性能。在我看来,它们在速度上都是相等的,因为Distinct()
方法将使用哈希表,而在内存中,我假设任何SQL查询将首先由。net优化,然后再执行。
我的假设是正确的吗?还是这两个命令的顺序仍然影响LINQ的性能?
至于如何运作…当你构建一个LINQ查询时,你基本上是在构建一个表达式树,但还没有执行任何东西。所以调用MyList.Distinct().OrderBy()
只会生成这个树,但不会执行它。(延期)。只有当你调用另一个函数如ToList()
时,表达式树才会被执行,并且运行库可以在执行表达式树之前优化表达式树。
对于LINQ to对象,即使我们假设OrderBy(...).Distinct()
和Distinct().OrderBy(...)
将返回相同的结果(这是不保证的),性能将取决于数据。
如果数据中有很多重复,首先运行Distinct
应该会更快。下一个基准测试显示(至少在我的机器上):
public class LinqBench
{
private static List<int> test = Enumerable.Range(1, 100)
.SelectMany(i => Enumerable.Repeat(i, 10))
.Select((i, index) => (i, index))
.OrderBy(t => t.index % 10)
.Select(t => t.i)
.ToList();
[Benchmark]
public List<int> OrderByThenDistinct() => test.OrderBy(i => i).Distinct().ToList();
[Benchmark]
public List<int> DistinctThenOrderBy()=> test.Distinct().OrderBy(i => i).ToList();
}
在我的机器上。net Core 3.1它给出:
StdDev | |||
---|---|---|---|
OrderByThenDistinct | 129.74 us | 2.120 us | 1.879 us |
distincttheenorderby | 19.58 us | 0.384 us | 0.794 us |
首先,seq.OrderBy(...).Distinct()
和seq.Distinct().OrderBy(...)
不能保证返回相同的结果,因为Distinct()
可能返回一个无序枚举。MS实现方便地保留了顺序,但是如果你向数据库传递一个LINQ查询,结果可能以DB引擎认为合适的任何顺序返回。
第二,在极端情况下,当你有很多重复(比如,五个值随机重复1,000,000次),你最好在OrderBy()
之前执行Distinct
。
长话短说,如果你希望你的结果是有序的,使用Distinct().OrderBy(...)
而不管性能。
我假设任何SQL查询将首先由。net优化,然后才得到>执行。
你认为这将如何工作,考虑到:
- 只有SQL执行端(服务器)知道这一点(即使用哪些索引),并且有一个查询优化器,应该根据表的统计数据优化已执行的查询。
- 你必须非常确定你没有以任何方式改变结果。
对不起,这没有意义——如果没有数据库的所有内部细节,c#中几乎没有可以安全地进行的优化,所以查询被发送到数据库进行分析。
因此,OrderBy或Distinct(尤其是Distinct)将影响性能——影响程度取决于OrderBy是否可以依赖索引。
或者这两个命令的顺序是否仍然影响LINQ的性能一般来说呢?
这里很有趣(你没有举例子)。
DISTINCT和ORDERBY在SQL中有特定的顺序,不管你在LINQ中是如何表述的。根据SQL定义,只有一种允许的语法。LINQ将查询放在一起并对其进行优化。如果你看一下语法,你会发现DISTINCT(至少是SQL Server的一个SQL术语)和OrderBy有一个特定的位置。
在另一边…
.Distinct () .OrderBy()和.OrderBy () .Distinct ()
有不同的结果。它们可以在SQL中完成(您可以使用Distinct的输出作为虚拟表,然后对其进行排序),但是它们具有不同的语义。除非你认为LINQ会神奇地读懂你的思想,否则编译器除了假设你有能力写出你所做的事情(只要它是合法的)并按照你给出的顺序执行这些步骤之外,没有任何上下文。
Except:在Queryable中Distinct的文档是明确的,这是不做的:
https://learn.microsoft.com/en-us/dotnet/api/system.linq.queryable.distinct?redirectedfrom=MSDN&视图=净- 5.0 # System_Linq_Queryable_Distinct__1_System_Linq_IQueryable___0__
表示Distinct返回一个无序列表。
所以,它们有一个根本的区别,它们不一样。