为什么EF查询数据需要很长时间才能加载到内存中?

时间:2013-10-27 09:31:53

标签: c# linq linq-to-entities entity-framework-5 sql-server-2012

我有一段代码执行一个非常大的查询,有很多连接,等等。为了简单起见,这里或多或少的结构:

var rootQuery = MainQuery(); // IQueryable<MyClass>
var jq1 = JoinQuery1(); // IQueryable<anonymous type>
var jq2 = JoinQuery2();
...
var jq6 = JoinQuery6();
var bigQuery = from x in rootQuery
               join j1 in jq1 on x.ID equals j1.MainID into join1
               from j1 in join1.DefaultIfEmpty()
               join j2 in jq2 on x.ID equals j2.MainID into join2
               from j2 in join1.DefaultIfEmpty()
               ...
               join j6 in jq6 on x.ID equals j6.MainID into join6
               from j6 in join1.DefaultIfEmpty()
               select new {
                            x.ID,
                            x.Field1,
                            j1.FieldA,
                            j2.FieldB,
                            ...
                            j6.FieldF
                          };
var sw = Stopwatch.StartNew();
var loadedData = bigQuery.ToList();
sw.Stop();
Console.WriteLine("Time Elapsed = {0} ms", sw.ElapsedMilliseconds);

秒表显示超过30秒,返回9行和约30列数据(没有文本字段)。所以我使用SQL Server Profiler嗅探了查询,实际上它是一个怪物。我摆弄并刺激并优化了一些索引,并使查询在200毫秒内执行。但是当我运行代码时,运行.ToList()仍然需要30秒以上,即使SQL Profiler说查询部分的时间不到200毫秒!

这里发生了什么?为什么.ToList需要这么长时间才能将如此小的数据集加载到内存中?

编辑:我解决了这个问题(请参阅下面的my answer),但我并不满意。回答任何可以提出更好方法的人,或者至少解释为什么对象实现如此昂贵以至于运行7个单独的查询并将它们加入本地内存会更便宜。

1 个答案:

答案 0 :(得分:1)

这看起来非常违反直觉,但我通过单独运行IQueryables解决了这个问题(使用Jon Skeet的整齐NullOr扩展名):

var rootQuery = MainQuery().ToList();
var jq1 = JoinQuery1().ToList();
var jq2 = JoinQuery2().ToList();
...
var jq6 = JoinQuery6().ToList();
var bigQuery = from x in rootQuery
           join j1 in jq1 on x.ID equals j1.MainID into join1
           from j1 in join1.DefaultIfEmpty()
           join j2 in jq2 on x.ID equals j2.MainID into join2
           from j2 in join1.DefaultIfEmpty()
           ...
           join j6 in jq6 on x.ID equals j6.MainID into join6
           from j6 in join1.DefaultIfEmpty()
           select new {
                x.ID,
                x.Field1,
                FieldA = j1.NullOr(j=>j.FieldA),
                FieldB = j2.NullOr(j=>j.FieldB),
                ...
                FieldF = j6.NullOr(j=>j.FieldF)
              };

现在,SQL端需要更长的时间(更多往返),但至少Linq-To-Entities方面几乎是即时的。

向任何可以解释这种奇怪行为的人回复信用!