我有这个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的性能非常差......你怎么看?
答案 0 :(得分:2)
您应该考虑抓住http://l2sprof.com/的试用版(如果您使用的是LINQ to SQL)或http://efprof.com/(如果您使用的是Entity Framework)并使用它来确定您的查询的SQL正在产生。
他们都是30天免费的,我希望有很多天可以解决这个问题。 ;)
Robert在评论中指出的另一种可能性是设置Log property on your DataContext,它将生成的SQL输出到你想要的任何地方。
您也可以使用SQL Server Profiler,它可能会显示超出您需要的内容,但是,嘿,它可能仍然可以完成工作。
答案 1 :(得分:1)
请记住,LINQ的执行会延迟,直到您枚举结果为止。在这种情况下,当您调用FirstOrDefault
时,它就是实际运行数据库查询的地方,这可能会解释延迟。
FirstOrDefault
不是2,而是整个查询。
考虑到这一点,如果您希望人们进一步缩小范围,您需要发布您的架构,数据等。
答案 2 :(得分:1)
首先,调用FirstOrDefault()所花费的时间是将Linq表达式树摘要为SQL,将该SQL发送到DB,在结果集中检索结果以及将该结果集映射到对象所花费的时间。这可能需要一段时间。
其次,我会描述数据库。执行跟踪并找出发送到此调用的数据库的确切SQL语句。如果该语句不包含FirstOrDefault限制的表示,例如SELECT TOP 1 ...
,则表示从表中提取所有记录只是为了丢弃除其中一个之外的所有记录。 Linq2SQL应该比这种情况更聪明;如果没有,请考虑升级到MSEF或NHibernate(一个查询的重要工作,我授予你,但如果这个语句没有产生有效的查询,那么任何类似的查询都不会有效。)
答案 3 :(得分:1)
将索引添加到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;
}
这里的想法基本上是:
FirstOrDefault
放在前面,然后强力输入,EBannersPosition.siderbar.ToString()
,答案 4 :(得分:1)
在我看来,你所见证的是dotTrace的一个问题。它报告了与Linq-To-Sql相关的任何事情的夸张时间。 (请参阅我对Best .NET memory and performance profiler?的评论)这不是唯一有这个问题的分析产品。
我自己也经历过,并且在此过程中很晚才尝试使用System.Diagnostics.StopWatch验证dotTrace的时间。当然,分析器无法像StopWatch一样报告准确的时序。但它们大幅度下降(某些因素)并且完全歪曲了代码所花费的时间(对于L2S部分)。
有些事实证明,总执行时间超过了实际的SQL Server工作量的几个因素。
请记住,Linq-To-Sql(L2S)本身会产生一些开销,有时可能很重要。 L2S为每个数据行创建对象并不像在对象上调用构造函数并填充其属性那么简单。不仅因为Model类不仅仅是简单的对象,还因为它对模式和数据类型以及诸如此类的东西进行了大量验证。
当然,编译查询本身可能需要相当长的时间。
因此,总而言之,尝试使用StopWatch获取时间。如果您可以验证我对dotTrace的声明,那么您可以分享一些结果会很好。
UPDATE1:你可以尝试的一件事是,不是在第一次运行时,而是在第二次运行代码时采用时序。只是为了确保你没有达到任何一次性成本。 此外,使用Linq,您始终可以选择使用已编译的查询。只是搜索一下。根据我的经验,你会得到同样不准确的结果。
关于编译查询的一个注意事项 - 如果不是绝对必要,请不要使用它们。它们有一些主要的缺点,如果你想要的话,就是一个简单的ORM。一个是,你失去了身份追踪。此外,您不能将它们用于WHERE expr IN(setexpr)类型查询(list.Contains(...)。当然,另一个是可读性。 最后,如果你打算使用它们,你可能想看看Nexterday的L2S自动编译(http://linqautocompiler.codeplex.com/)