[英]Overhead with Linq-to-SQL
我们目前正在用ASP.NET MVC 4编写的网站遇到性能问题,特别是有关Linq-to-SQL的开销,因此(除其他因素外)导致每个Linq-to页面请求的CPU跳到100% -SQL被使用。
我正在使用ANTS Performance Profiler 8.5 Pro分析该应用程序,并且在开发和生产环境中都遇到了相同的结果。 但是,与开发环境相比,生产环境中的性能要差得多。
通过ANTS,在实例化Linq-to-SQL数据上下文并执行非常简单的查询(例如)时,我似乎已将其范围缩小到了开销:
using (var db = new D.DataClassesDataContext(ConfigurationManager.ConnectionStrings["Master"].ConnectionString))
{
db.ObjectTrackingEnabled = false;
HttpContext.Cache["WebPageTemplateCapabilities"] = (from x in db.Clients
where x.ClientID == this.ClientID
select x.WebPageTemplateCapabilities).SingleOrDefault();
}
我一辈子都无法弄清楚为什么像这样的简单查询会导致如此高的性能。 此代码段最多需要1.5秒才能运行,与在SSMS中执行的同一查询相比,这是疯狂的。 我现在假设CPU使用率过高可能是由于该网站进行的任何数据库通信所致。
我想念什么? 这是为了记录在网站生命周期中实例化和执行的第一个数据上下文。
如果您使用Linq to SQL并且您多次调用同一查询,那么我建议您使用编译函数。 上面的查询可以编写如下:
private static Func<DataClassesDataContext, string, string> MyCompiledFunction =
CompiledQuery.Compile((DataClassesDataContext pContext, string pClientID) =>
(from x in pContext.Clients
where x.ClientID == pClientID
select x.WebPageTemplateCapabilities).SingleOrDefault();
您没有指定返回类型或客户端ID,所以我假设它们是字符串。
请注意,在第一次编译函数时会产生开销-在此之后,它的速度大大提高,我们的代码速度提高了5到6倍。 如果它只被调用过一次,那就不要打扰。
问题是您正在使用SingleOrDefault
。 该方法必须保证只有一个结果与您的查询匹配。 您应该改用FirstOrDefault
来获取第一个条目(如果有)。
我还将避免为同一请求打开多个数据库连接(由于您仅对该查询使用专用连接,所以您似乎这样做了)。
而是为所有与HTTP请求相关的查询共享相同的连接。 确实存在ADO.NET连接池,但是它仍然会给您带来开销。 特别是当有多个用户浏览您的网站时。
您可以使用HTTP模块
public class ConnectionModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest += OnBeginRequest;
context.EndRequest += OnEndRequest;
}
private void OnEndRequest(object sender, EventArgs e)
{
var db = ((HttpApplication)sender).Context.Items["DbConnection"] as IDbConnection;
if (db != null)
db.Dispose();
}
private void OnBeginRequest(object sender, EventArgs e)
{
var conString = ConfigurationManager.ConnectionStrings["Master"].ConnectionString;
var connection = new SqlConnection(conString);
connection.Open();
((HttpApplication)sender).Context.Items["DbConnection"] = connection;
}
public void Dispose()
{
}
}
现在,您可以使用以下方法从任何地方访问连接:
var connection = (IDbConnection)HttpContext.Current.Items["DbConnection"];
您当然可以用您的DbContext
代替连接。
至于工作单位。 在我的世界中,HTTP请求始终代表一个工作单元。 如果不是,则HTTP请求范围太广。 (但这当然取决于您如何设计您的网站)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.