2013-04-26 24 views
5

我将LINQ to SQL结果投影到强类型类:Parent和Child。这两个查询之间的性能差异很大:一对多预测LINQ查询重复执行

慢查询 - 从DataContext的记录显示,到数据库单独调用正在为每个父母所作出

var q = from p in parenttable 
     select new Parent() 
     { 
      id = p.id, 
      Children = (from c in childtable 
         where c.parentid = p.id 
         select c).ToList() 
     } 
return q.ToList() //SLOW 

快速查询 - 从DataContext的节目记录返回所有需要的数据

var q = from p in parenttable 
     select new Parent() 
     { 
      id = p.id, 
      Children = from c in childtable 
         where c.parentid = p.id 
         select c 
     } 
return q.ToList() //FAST 

我想迫使LINQ到使用第二个示例的单查询的风格,但与他们的孩子填充父类的单个数据库命中查询词直接对象。否则,Children属性是IQuerierable<Child>,必须查询它以公开Child对象。

被引用的问题似乎没有解决我的情况。使用db.LoadOptions不起作用。也许它要求类型是用DataContext注册的TEntity。

DataLoadOptions options = new DataLoadOptions(); 
    options.LoadWith<Parent>(p => p.Children); 
    db.LoadOptions = options; 

请注意:父母与子女是简单类型,不Table<TEntity>类型。父母与子女之间没有上下文关系。子查询是特设的。

问题的关键:在第二个LINQ示例中,我实现了IQueriable语句,并且不会调用ToList()函数,并且出于某种原因,LINQ知道如何生成一个可以检索所需数据的单个查询。我如何使用实际数据填充我的临时投影,就像在第一个查询中完成的一样?另外,如果有人能帮助我更好地说出我的问题,我将不胜感激。

+0

“Child”如何成为“简单类型”?它应该是一个映射类型。并且'parenttable'是一个'Table'还是前一个linq查询的结果?一些linq语句会导致L2S从连接切换到N + 1。 – 2013-04-26 20:09:06

+1

重复标记:你知道实体框架和LINQ到SQL的区别吗? – 2013-04-27 06:54:52

+0

@GertArnold虽然EF/L2S的LINQ部分经常会使功能上类似的问题重复,但在这种情况下,我相信你是完全正确的;他们不是重复的。重启。 – 2013-04-29 13:48:03

回答

0

您必须为您的数据加载设置正确的选项。

options.LoadWith<Document>(d => d.Metadata); 

this

附: Include仅限于LINQToEntity

+0

这看起来应该是答案,但它不适合我。我试过dlo.LoadWith (p => p.Children)。仍然有多个数据库匹配 – Paul 2013-04-26 16:10:24

+0

@Paul你不需要使用父表。您是否通过LINQ2SQL生成了实体父项?然后,当您从上下文请求Parent时,您的实体已经包含Children。 – 2013-04-26 16:44:20

0

第二个查询很快恰恰是因为孩子没有被填充。

而第一个很慢只是因为孩子们正在人口稠密。

选择最适合您需求的产品,您根本无法将它们的功能放在一起!

编辑:

由于@Servy说:

在你的第二个查询,你实际上并没有获取有关孩子的任何信息。您已经创建了查询,但是您并未实际执行它们以获取这些查询的结果。如果您要迭代列表,然后遍历每个项目的Children集合,则会看到它花费的时间与第一个查询相同。

1

我发现完成此操作的最快方法是执行一个查询,返回所有结果,然后对所有结果进行分组。确保在第一个查询上执行.ToList(),以便第二个查询不会执行多次调用。

这里r应该有你想要完成的只有一个数据库查询。

  var q = from p in parenttable 
        join c in childtable on p.id equals c.parentid 
        select c).ToList(); 
      var r = q.GroupBy(x => x.parentid).Select(x => new { id = x.Key, Children=x }); 
+1

而不是做一个加入然后一个小组,然后使用一个GroupJoin。 – Servy 2013-04-29 14:14:18

5

重要的是要记住,LINQ查询依赖于延迟执行是很重要的。在你的第二个查询中,你实际上并没有获取关于这些孩子的任何信息。您已经创建了查询,但是您并未实际执行它们以获取这些查询的结果。如果您要迭代列表,然后遍历每个项目的Children集合,则会看到它花费的时间与第一个查询相同。

你的查询本身效率很低。您正在使用嵌套查询来表示Join关系。如果使用Join代替,查询将能够被查询提供者以及数据库相应地优化,以更快地执行。您可能还需要调整数据库上的索引以提高性能。以下是加入可能的外观:

var q = from p in parenttable 
     join child in childtable 
     on p.id equals child.parentid into children 
     select new Parent() 
     { 
      id = p.id, 
      Children = children.ToList(), 
     } 
return q.ToList() //SLOW 
+0

我知道这个问题是关于LINQ to SQL的,但是我想我会提到如果你使用的是Entity Framework,'Children'上不需要'ToList()'。 – 2013-04-29 14:40:56