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();
}
}
}
输出(毫秒(
循环 | Join 1 | Join 2 | |
---|---|---|---|
1 | 34262 | 28334||
2 | 10614 | 24367 | |
3 | 11760 | 22715 | |
4 | 9945 | 31258 | |
5 | 12717 | 32469 | |
6 | 8550 | 24521 | |
7 | 3392 | 8936 | |
8 | 1672 | 5140||
9 | 11028 | 3256 | |
10 | 10929 | 15162 |
您的测试在说明连接的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中连接迭代器到对象的实际实现