内部联接事项中的列表顺序用于性能


using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
for (int i = 1; i < 11; i++)
{
Console.WriteLine("------{0} loop------", i);
System.Threading.Thread.Sleep(500);
List<int> numberList1 = new List<int>();
for (int j = 1; j < 10; j++)
{
numberList1.Add(new Random().Next(1, 10000));
}
List<int> numberList2 = new List<int>();
for (int j = 1; j < 10000; j++)
{
numberList2.Add(new Random().Next(1, 10000));
}
Stopwatch sw = Stopwatch.StartNew();
var temp1 = (from n1 in numberList1
join n2 in numberList2
on n1 equals n2
select n2).ToList();
sw.Stop();
Console.WriteLine("Time: {0}", sw.ElapsedTicks);
System.Threading.Thread.Sleep(500);
sw.Reset();
sw.Start();
var temp2 = (from n2 in numberList2
join n1 in numberList1
on n2 equals n1
select n2).ToList();
sw.Stop();
Console.WriteLine("Time: {0}", sw.ElapsedTicks);
}
Console.ReadKey();
}
}
}

输出(毫秒(

283345140
循环Join 1Join 2
134262
21061424367
31176022715
4994531258
51271732469
6855024521
733928936
81672
9110283256
101092915162

您的测试在说明连接的linq-to-objects行为方面没有错。如果你仔细想想,你会如何实现它?虽然没有任何额外的类似索引,但您唯一的选择是使用两个嵌套循环来查找匹配的元素。在你的测试中,你有一个小集合编号List1和一个大集合编号List2,所以基本上你有:

foreach(var n1 in numberList1)
foreach(var n1 in numberList2)

在第一种情况下,其他情况在第二种情况下。

您可以通过将其中一个集合转换为查找来做得更好——本质上是通过迭代一次并在循环中使用它来创建索引:

var lookup = createLookup(numberList2, getKeyFromN2)
foreach(var n1 in numberList1)
{
var n2 = lookup[getKeyFromN1(n1)];

现在,关于这些集合的大小,最好为较大的集合创建一个查找,并在项目数较少的循环中使用它。

至于这个测试和任何数据库引擎的相关性,它并没有。数据库引擎有很多关于表的元数据,这些元数据可以像索引和统计信息一样显著提高性能,如果设置正确,联接的顺序将无关紧要,因为如果sql引擎认为这是有利的,它只会交换该顺序-尽管联接的顺序在sql server中确实很重要,但我不记得他们实现"智能"查询执行器。

linq中连接迭代器到对象的实际实现

最新更新