为什么这个简单的 linq 查询需要这么多时间?

发布于 2024-10-28 09:35:32 字数 1924 浏览 0 评论 0原文

我有这个 linq 查询:

 public static Banner getSideBarBanner(){
    DataClassesDataContext db = new DataClassesDataContext();
    var bannerSiderBar = (from b in db.Banners
                  where b.Position.Equals(EBannersPosition.siderbar.ToString())
                  && b.Visible == true
                  select b).FirstOrDefault();
    return bannerSiderBar;
}

嗯,我使用 dotTrace 来分析应用程序,我发现查询执行需要很长时间(超过 2 秒)

在此处输入图像描述

我只是想知道,为什么要花这么多时间,尤其是当我的 Banner 表有大约 30 条记录时!

预先感谢您的意见...

更新: Banner 的表架构:

在此处输入图像描述

更新 2:如果我使用简单的 SQL 连接而不是 linq,则查询执行需要 700 毫秒这是一个巨大的改进...

 public static Banner getSideBarBanner()
{
    Banner bannerFound = new Banner();
    SqlConnection myConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["Library_prodConnectionString"].ConnectionString);
    try
    {
        myConnection.Open();
        SqlCommand myCommand = new SqlCommand("SELECT path, link FROM Banner b WHERE b.Position = @position AND b.Visible = 1 ", myConnection);
        myCommand.Parameters.Add(new SqlParameter("@position", EBannersPosition.siderbar.ToString()));
        SqlDataReader myReader = myCommand.ExecuteReader();
        while (myReader.Read())
        {
            if (myReader["path"] != null)
                bannerFound.Path = myReader["path"].ToString();
            if (myReader["link"] != null)
                bannerFound.Link = myReader["link"].ToString();
        }
        myConnection.Close();
    }
    catch (Exception e)
    {
        CreateLogFiles Err = new CreateLogFiles();
        Err.ErrorLog(HttpContext.Current.Server.MapPath("~/Site/Logs/ErrorLog"), e.ToString());
    }
    return bannerFound;
}

这告诉我 linq 查询到 sql 的翻译性能非常差...您觉得怎么样?

I have this linq query:

 public static Banner getSideBarBanner(){
    DataClassesDataContext db = new DataClassesDataContext();
    var bannerSiderBar = (from b in db.Banners
                  where b.Position.Equals(EBannersPosition.siderbar.ToString())
                  && b.Visible == true
                  select b).FirstOrDefault();
    return bannerSiderBar;
}

well, I use dotTrace to profile the application and I see that the query execution takes a lot of time (over 2s)

enter image description here

I am simply wondering, why so much time especially when my Banner table has about 30 records!!!

Thanks in advance for your opionions...

UPDATE:
Banner's table schema:

enter image description here

UPDATE 2: If I use simple SQL connection instead of linq, the query execution takes 700ms which is a huge improvement...

 public static Banner getSideBarBanner()
{
    Banner bannerFound = new Banner();
    SqlConnection myConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["Library_prodConnectionString"].ConnectionString);
    try
    {
        myConnection.Open();
        SqlCommand myCommand = new SqlCommand("SELECT path, link FROM Banner b WHERE b.Position = @position AND b.Visible = 1 ", myConnection);
        myCommand.Parameters.Add(new SqlParameter("@position", EBannersPosition.siderbar.ToString()));
        SqlDataReader myReader = myCommand.ExecuteReader();
        while (myReader.Read())
        {
            if (myReader["path"] != null)
                bannerFound.Path = myReader["path"].ToString();
            if (myReader["link"] != null)
                bannerFound.Link = myReader["link"].ToString();
        }
        myConnection.Close();
    }
    catch (Exception e)
    {
        CreateLogFiles Err = new CreateLogFiles();
        Err.ErrorLog(HttpContext.Current.Server.MapPath("~/Site/Logs/ErrorLog"), e.ToString());
    }
    return bannerFound;
}

This tells me that translation of the linq query to sql has a very poor performance...What do you think?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

久光 2024-11-04 09:35:32

您应该考虑获取 http://l2sprof.com/ 的试用版(如果您使用的是 LINQ to SQL)或http://efprof.com/(如果您使用的是实体框架)并使用它来找出您的 SQL正在生成查询。

它们都可以免费使用 30 天,我希望这段时间有足够的时间来解决这个问题。 ;)

罗伯特在评论中指出的另一种可能性是设置 DataContext 上的 Log 属性,它将生成的 SQL 输出到您想要的任何位置。

您也可以只使用 SQL Server Profiler,它可能会显示比您需要的更多的内容,但是,嘿,它可能仍然可以完成工作。

You should consider grabbing the trial for http://l2sprof.com/ (if you're using LINQ to SQL) or http://efprof.com/ (if you're using Entity Framework) and using that to figure out what SQL your query is generating.

They're both free for 30 days, which I hope would be plenty of days to figure out this problem. ;)

Another possibility, pointed out by Robert in the comments, is to set the Log property on your DataContext, which will output the generated SQL to wherever you want.

You also could just use the SQL Server Profiler, which probably will display much more than you need, but hey, it would probably still get the job done.

看海 2024-11-04 09:35:32

请记住,LINQ 的执行会延迟,直到您枚举结果为止。在这种情况下,当您调用 FirstOrDefault 时,这就是它实际运行数据库查询的地方,这可能解释了延迟。

并不是 FirstOrDefault 花费了 2 秒,而是整个查询花费了 2 秒。

考虑到这一点,如果您希望人们进一步缩小范围,您需要发布您的架构、数据等。

Remember that LINQ is delayed in execution until you enumerate through the results. In this case, when you call FirstOrDefault, that's where it is actually running the database query, which might explain the delay.

It's not that FirstOrDefault is taking 2s, it's that the entire query is.

With that in mind, if you want people to narrow down further, you'll need to post your schema, data, etc.

初熏 2024-11-04 09:35:32

首先,调用 FirstOrDefault() 所花费的时间是将 Linq 表达式树消化为 SQL、将该 SQL 发送到数据库、检索结果集中的结果以及将该结果集映射到对象所花费的时间。这可能需要一段时间。

其次,我会分析数据库。进行跟踪并找出为此调用发送到数据库的确切 SQL 语句。如果该语句不包含 FirstOrDefault 限制的表示,例如 SELECT TOP 1 ...,则您将从表中提取所有记录,只是为了丢弃除其中一条记录之外的所有记录。 Linq2SQL 应该比这种情况更聪明;如果没有,请考虑升级到 MSEF 或 NHibernate(我同意,对于一个查询来说这是一项艰巨的工作,但如果此语句不能生成有效的查询,那么任何类似的查询也不会有效)。

First off, the time spent calling FirstOrDefault() is the time spent digesting the Linq expression tree into SQL, sending that SQL to the DB, retrieving the result in a result set, and mapping that result set to an object. That can take a while.

Second, I would profile the database. Do a trace and figure out the exact SQL statement sent to the DB for this call. If that statement does not include a representation of the FirstOrDefault limitation, such as SELECT TOP 1 ..., you're pulling ALL the records out of the table just to discard all but one of them. Linq2SQL should be smarter than that in this case; if not, look into upgrading to MSEF or NHibernate (a big job for just one query, I grant you, but if this statement isn't producing an efficient query then any query like it won't be efficient either).

美胚控场 2024-11-04 09:35:32

Position 添加索引,然后尝试以下操作:

 public static Banner getSideBarBanner()
 {
    DataClassesDataContext db = new DataClassesDataContext();

    string thisPosition = EBannersPosition.siderbar.ToString();

    var bannerSiderBar 
        = db.Banners.FirstOrDefault<Banner>
             (x => x.Position == thisPosition && x.Visible);

    return bannerSiderBar;
}

基本上,这里的想法是:

  1. FirstOrDefault 放在前面并使其成为强类型,并
  2. 删除 < 的多次执行代码>EBannersPosition.siderbar.ToString(),

Add an index to Position, and try this:

 public static Banner getSideBarBanner()
 {
    DataClassesDataContext db = new DataClassesDataContext();

    string thisPosition = EBannersPosition.siderbar.ToString();

    var bannerSiderBar 
        = db.Banners.FirstOrDefault<Banner>
             (x => x.Position == thisPosition && x.Visible);

    return bannerSiderBar;
}

Basically the ideas here are to:

  1. Put the FirstOrDefault up front and make it strongly-typed, and
  2. remove the multiple executions of EBannersPosition.siderbar.ToString(),
婴鹅 2024-11-04 09:35:32

在我看来,您所看到的是 dotTrace 的问题。它报告与 Linq-To-Sql 相关的任何内容的夸大时间。 (请参阅我对最佳 .NET 内存和性能分析器? 的评论)它并不是唯一存在此问题的分析产品。

我自己也经历过这种情况,只是在过程的最后阶段才尝试使用 System.Diagnostics.StopWatch 验证 dotTrace 的时间。当然,探查器无法像秒表那样报告准确的计时。但它们相差很大(某些因素),并且完全歪曲了代码所花费的时间(对于 L2S 部分)。

总执行时间超出实际 SQL Server 工作量的事实在一定程度上证明了这一点。

但请记住,Linq-To-Sql (L2S) 本身会产生一些开销,有时可能会很大。
L2S 为每个数据行创建对象并不像调用对象的构造函数并填充其属性那么简单。不仅因为模型类不仅仅是简单的对象,还因为它对模式和数据类型等进行了大量验证。

当然,查询本身的编译可能需要相当长的时间。

因此,总而言之,尝试使用秒表来获取计时。如果您能验证我关于 dotTrace 的说法,那么如果您能分享一些结果,那就太好了。

UPDATE1:您可以尝试的一件事是,不要在第一次运行时计时,而是在第二次运行代码时计时。只是为了确保您不会产生任何一次性成本。
此外,使用 Linq,您始终可以选择使用编译查询。只要稍微搜索一下即可。根据我的经验,你会得到同样不准确的结果。

关于编译查询的一点注释 - 如果不是绝对必要,请不要使用它们。它们有一些主要缺点,如果您正在寻找的是简单的 ORM,那么它们也有一些缺点。一是,你失去了身份追踪。另外,您不能将它们用于 WHERE expr IN (setexpr) 类型的查询 (list.Contains(...)。当然,另一个问题是可读性。
最后,如果您打算使用它们,您可能需要查看 Nexterday 的 L2S 自动编译 (http://linqautocompiler .codeplex.com/

What you are witnessing, is, in my opinion, a problem with dotTrace. It reports exaggerated times for anything that is related to Linq-To-Sql. (See my comments on Best .NET memory and performance profiler?) It is not the only profiling product out there that has this problem.

I have experienced that myself and only very late in the process tried to verify the times of dotTrace with the System.Diagnostics.StopWatch. Of course, a profiler cannot report as accurate timings as StopWatch. But they were off by a large margin (some factors) and completely misrepresent the time taken by your code (for the L2S part).

It is somewhat evidenced by the fact that the total execution time exceeds the actual SQL Server work by a few factors.

Keep in mind though, that Linq-To-Sql (L2S) itself incurs some overhead, which can be significant at times.
The object creation by L2S for each data row is not as simple as calling a constructor on an object and populating its properties. Not only because the Model classes are more than simple objects but also because it does a lot of verification of schema and datatypes and whatnot.

And of course, the compilation of the queries themselves can take quite some time.

So, in summary, try to get timings by using StopWatch. It would be good if you could share some results if you can verify my claims about dotTrace.

UPDATE1: One thing you could try, is to take the timings not on the first run, but on the second run of the code. Just to make sure you don't hit any one-time-costs.
Also, with Linq, you always have the option to use compiled queries. Just search around for that a bit. In my experience you'll get the same inaccurate results though.

One note on compiled queries - don't use them, if not absolutely necessary. They have some major disadvantages, if all, that you are looking for, is a simple ORM. One is, you lose identity tracking. Also, you cannot use them for WHERE expr IN (setexpr)-type queries (list.Contains(...). Another one, of course, is readability.
And finally, if you are going to use them, you might want to look at Nexterday's autocompilation for L2S (http://linqautocompiler.codeplex.com/)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文