繁体   English   中英

如何优化这个linq查询?

[英]How to optimize this linq query?

我有以下linq查询:

var allnews = from a in db.News
                              where !(from c in db.NewsViews
                                      where c.UserGuid == thisUser.UserGuid
                                      select c.NewsGuid).Contains(a.NewsGuid)
                              orderby a.Date descending
                              select a;

我想知道优化它的最佳方法是什么? 或者查询分析器会为我做那个吗?

编辑:想法是获取用户尚未看到的所有新闻项目。 因此,一旦用户看到一个项目,我就将该项目存储在NewsViews中。 新闻本身就在新闻中。

子查询似乎不使用a ,所以

      //untested
      var allnews = from a in db.News
                    let excluders = from c in db.NewsViews
                                    where c.UserGuid == thisUser.UserGuid
                                    select c.NewsGuid   
                          where !excluders.Contains(a.NewsGuid)
                          orderby a.Date descending
                          select a;

但是请注意,您现在正在通过LINQ进行SQL优化(顺便说一句,这是L2S还是EF?)。
而正常的SQL优化很难。 您必须使用实际数据进行测量和分析。 @ Joachim的多内连接子查询方法很可能更好。

而不是使用contains,您可以添加到内部查询的where-statement:

...和c.newsguid == a.newsguid

和。内部查询的任何()

var allnews = from a in db.News
                  where !(from c in db.NewsViews
                          where c.UserGuid == thisUser.UserGuid
                            and c.NewsGuid == a.NewsGuid).Any()
                   orderby a.Date descending
                   select a;

我假设目标是按降序日期顺序检索NewsView:

db.News.OrderByDescending(a => a.Date).NewsViews;

当然,这假设您已经在模型中在News和NewsViews实体之间建立了关联。 通过提前设置关联,子查询变得不必要。

更新:

我一直在使用LINQ-to-SQL大约18个月,而且我一直在使用与你在NOT IN查询中说明的结构相同的结构。 正如我之前所说的,如果你提前在模型中设置关联并使用数据库本身的索引,你可能会遇到一点性能提升,但从LINQ的角度来看,我相信你已经像你一样优化了。在不诉诸不必要的神秘查询语句的情况下重新开始。

这是另一种选择:

from newsitem in db.News
join viewing in (
       from viewing in db.NewsViews
       where viewing.UserGuid == thisUser.UserGuid
       select viewing
) on newsitem.NewsGuid equals viewing.NewsGuid into usersviewings
where !usersviewings.Any()
orderby newsitem.Date descending
select newsitem;

但至于这是否更快 - 这是任何人的猜测; 试试吧。 从根本上说,你正在进行左连接,左边的部分被过滤掉了,不能返回任何结果 - 那些索引不好,AFAIK。 执行引擎需要扫描新闻集中的所有行,如果您受SQL支持,则表扫描不是您的朋友。 话虽如此,除非你真的希望这是一个巨大的桌子,它可能并不重要,特别是如果你只报告前N个命中...

也许这是我对linq知识的缺乏,但也许是一个左连接,其中NewsViews中的列为空? 这似乎比制作子查询并比较两者更好。

你可以在这里做的最好的优化动作是允许从NewsViews导航到新闻......由于一个不存在,我不得不对优化有所了解。

db.News.Join(db.News.Select(n => n.NewsGuid)
    .Except(db.NewsViews
        .Where(c => c.UserGuid == thisUser.UserGuid)
        .Select(c => c.NewsGuid)
    ), n1 => n1.NewsGuid, n2 => n2, (n1, n2) => new { n1 = n1, n2 = n2 })
    .Select(anon => anon.n1);

当您尝试执行列表不包含其他列表的查询时,Except将生成性能最佳的 SQL。 由于没有从NewsView导航到新闻,我们不得不欺骗内部加入返回新闻。

可以做到的另一种方式是我的朋友GroupJoin。

db.News
    .GroupJoin(db.NewsViews, n => n.NewsGuid, nv => nv.NewsGuid, (n, nv) => new { News = n, NewsViewList = nv })
    .Where(anon => anon.NewsViewList != null) // I don't remember the best test here, either it's not null, or the count > 0 :-)
    .OrderByDescending(anon => anon.News.Date)
    .Select(anon => anon.News);

这就是我至少要做到的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM