LinQ to SQL 及 non-LinQ方式实现Group的Performance对比
拥有476550数据的一张数据表。使用其中的某个字段分组,然后按该字段进行排序。该需求分别使用LinQ to SQL和non-LinQ的方式实现,然后来看一下performance对比。
LinQ way
from p in context.Part_Part group p by p.FunctionGroup into groupedPs orderby groupedPs.Key select groupedPs
non-LinQ way
var results = new SortedDictionary<long?, IList<Part_Part>>(); foreach (var p in context.Part_Part) { IList<Part_Part> groupedValue = null; if (!results.TryGetValue(p.FunctionGroup, out groupedValue)) { groupedValue = new List<Part_Part>(); results[p.FunctionGroup] = groupedValue; } groupedValue.Add(p); }
从
var results = new SortedDictionary<long?, IList<Part_Part>>();
可以看出,用来排序的字段类型为long?。先看一下执行时间。
LinQ Way | non-LinQ Way | |
first time | 1:6.698 | 6.707 |
second time | 1:7.404 | 1.426 |
third time | 1:7.127 | 1.486 |
forth time | 1:6.952 | 1.425 |
明显可以看出在这个scenario下,LinQ的performance极低。调整代码,这次使用类型为string的PartDescription分组。测试,结果如下。
LinQ Way | non-LinQ way | |
first time | >30min | 8.738 |
second time | >30min | 4.201 |
third time | >30min | 4.173 |
forth time | >30min | 4.176 |
这个scenario下,non-LinQ way耗时有所增加,而LinQ way更是惨不忍睹。甚至在苦苦的等了30分钟不见结果后,提早结束了测试程序。
可见,LinQ在带来简洁风和极佳可读性的同时,也带来了性能的损耗。看一段来自于《LinQ in Action》中,关于LinQ性能问题的描述。
There are no surprises. LINQ does not come for free. LINQ queries cause additional work, object creations, and pressure on the garbage collector. The additional cost of using LINQ can vary a lot depending on the query. It can be as low as 5 percent, but can sometimes be around 500 percent.
既如此,以后还能不能愉快的使用LinQ呢?再来看一段《LinQ in Action》中的描述。
Do not be afraid to use LINQ, but use it wisely. For simple operations that are executed extensively in your code, you may consider using the traditional alternatives. For simple filter or search operations, you can stick to the methods offered by List<T> and arrays, such as FindAll, ForEach, Find, ConvertAll, or TrueForAll. Of course, you can continue to use the classic for and foreach statements wherever LINQ would be overkill. For queries that are not executed several times per second, you can probably use LINQ to Objects safely. A query that is executed only once in a non-time-critical context won't make a big difference if it takes 60 milliseconds to execute instead of 10.