C# 实体框架(6)绩效优化建议
我的应用程序中有一个ADO.Net数据访问层,它使用基本ADO.Net和CRUD存储过程(每个操作一个,例如Select_myTable、Insert_myTable)。您可以想象,在一个大型系统(如我们的系统)中,DA层所需的DB对象数量相当大 我一直在研究将层类重构为EF POCO类的可能性。我已经设法做到了,但当我尝试进行性能测试时,它变得非常可怕。使用下面的类(创建对象、将Key设置为所需的值、调用dataselect),100000次数据加载只需要大约47秒(数据库中只有少量记录)。而存储的Proc方法大约需要7秒 我正在寻找关于如何优化这一点的建议——值得注意的是,我不能更改层的公开功能——只能更改它如何实现方法(即,我不能将上下文所有权的责任传递给BO层) 谢谢C# 实体框架(6)绩效优化建议,c#,.net,performance,entity-framework,entity-framework-6,C#,.net,Performance,Entity Framework,Entity Framework 6,我的应用程序中有一个ADO.Net数据访问层,它使用基本ADO.Net和CRUD存储过程(每个操作一个,例如Select_myTable、Insert_myTable)。您可以想象,在一个大型系统(如我们的系统)中,DA层所需的DB对象数量相当大 我一直在研究将层类重构为EF POCO类的可能性。我已经设法做到了,但当我尝试进行性能测试时,它变得非常可怕。使用下面的类(创建对象、将Key设置为所需的值、调用dataselect),100000次数据加载只需要大约47秒(数据库中只有少量记录)。而
public class DAContext : DbContext
{
public DAContext(DbConnection connection, DbTransaction trans)
: base(connection, false)
{
this.Database.UseTransaction(trans);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
//Stop Pluralising the Object names for table names.
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
//Set any property ending in "Key" as a key type.
modelBuilder.Properties().Where(prop => prop.Name.ToLower().EndsWith("key")).Configure(config => config.IsKey());
}
public DbSet<MyTable> MyTable{ get; set; }
}
public class MyTable : DataAccessBase
{
#region Properties
public int MyTableKey { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool Active { get; set; }
public int CreatedBy { get; set; }
public DateTime CreatedDate { get; set; }
public int ModifiedBy { get; set; }
public DateTime ModifiedDate { get; set; }
#endregion
#region constructors
public MyTable()
{
//Set Default Values.
Active = true;
Name = string.Empty;
CreatedDate = DateTime.MinValue;
ModifiedDate = DateTime.MinValue;
}
#endregion
#region Methods
public override void DataSelect(System.Data.SqlClient.SqlConnection connection, System.Data.SqlClient.SqlTransaction transaction)
{
using (DAContext ctxt = new DAContext(connection, transaction))
{
var limitquery = from C in ctxt.MyTable
select C;
//TODO: Sort the Query
limitquery = FilterQuery(limitquery);
var limit = limitquery.FirstOrDefault();
if (limit != null)
{
this.Name = limit.Name;
this.Description = limit.Description;
this.Active = limit.Active;
this.CreatedBy = limit.CreatedBy;
this.CreatedDate = limit.CreatedDate;
this.ModifiedBy = limit.ModifiedBy;
this.ModifiedDate = limit.ModifiedDate;
}
else
{
throw new ObjectNotFoundException(string.Format("No MyTable with the specified Key ({0}) exists", this.MyTableKey));
}
}
}
private IQueryable<MyTable1> FilterQuery(IQueryable<MyTable1> limitQuery)
{
if (MyTableKey > 0) limitQuery = limitQuery.Where(C => C.MyTableKey == MyTableKey);
if (!string.IsNullOrEmpty(Name)) limitQuery = limitQuery.Where(C => C.Name == Name);
if (!string.IsNullOrEmpty(Description)) limitQuery = limitQuery.Where(C => C.Description == Description);
if (Active) limitQuery = limitQuery.Where(C => C.Active == true);
if (CreatedBy > 0) limitQuery = limitQuery.Where(C => C.CreatedBy == CreatedBy);
if (ModifiedBy > 0) limitQuery = limitQuery.Where(C => C.ModifiedBy == ModifiedBy);
if (CreatedDate > DateTime.MinValue) limitQuery = limitQuery.Where(C => C.CreatedDate == CreatedDate);
if (ModifiedDate > DateTime.MinValue) limitQuery = limitQuery.Where(C => C.ModifiedDate == ModifiedDate);
return limitQuery;
}
#endregion
}
公共类DAContext:DbContext
{
公共DAContext(数据库连接、数据库事务传输)
:底座(连接,错误)
{
this.Database.useTransation(trans);
}
模型创建时受保护的覆盖无效(DbModelBuilder modelBuilder)
{
基于模型创建(modelBuilder);
//停止对表名称的对象名称进行多元化。
modelBuilder.Conventions.Remove();
//将任何以“Key”结尾的属性设置为键类型。
modelBuilder.Properties().Where(prop=>prop.Name.ToLower().EndsWith(“key”)).Configure(config=>config.IsKey());
}
公共DbSet MyTable{get;set;}
}
公共类MyTable:DataAccessBase
{
#区域属性
公共int MyTableKey{get;set;}
公共字符串名称{get;set;}
公共字符串说明{get;set;}
公共bool活动{get;set;}
public int CreatedBy{get;set;}
公共日期时间CreatedDate{get;set;}
公共int被{get;set;}修改
公共日期时间修改日期{get;set;}
#端区
#区域构造函数
公共MyTable()
{
//设置默认值。
主动=真;
Name=string.Empty;
CreatedDate=DateTime.MinValue;
ModifiedDate=DateTime.MinValue;
}
#端区
#区域方法
public override void DataSelect(System.Data.SqlClient.SqlConnection连接,System.Data.SqlClient.SqlTransaction)
{
使用(DAContext ctxt=新的DAContext(连接、事务))
{
var limitquery=来自ctxt.MyTable中的C
选择C;
//TODO:对查询进行排序
limitquery=FilterQuery(limitquery);
var limit=limitquery.FirstOrDefault();
如果(限制!=null)
{
this.Name=limit.Name;
this.Description=limit.Description;
this.Active=limit.Active;
this.CreatedBy=limit.CreatedBy;
this.CreatedDate=limit.CreatedDate;
this.ModifiedBy=limit.ModifiedBy;
this.ModifiedDate=limit.ModifiedDate;
}
其他的
{
抛出新的ObjectNotFoundException(string.Format(“不存在具有指定键({0})的MyTable,this.MyTableKey));
}
}
}
专用IQueryable筛选器查询(IQueryable limitQuery)
{
如果(MyTableKey>0)limitQuery=limitQuery.Where(C=>C.MyTableKey==MyTableKey);
如果(!string.IsNullOrEmpty(Name))limitQuery=limitQuery.Where(C=>C.Name==Name);
如果(!string.IsNullOrEmpty(Description))limitQuery=limitQuery.Where(C=>C.Description==Description);
if(Active)limitQuery=limitQuery.Where(C=>C.Active==true);
如果(CreatedBy>0)limitQuery=limitQuery.Where(C=>C.CreatedBy==CreatedBy);
如果(ModifiedBy>0)limitQuery=limitQuery.Where(C=>C.ModifiedBy==ModifiedBy);
如果(CreatedDate>DateTime.MinValue)limitQuery=limitQuery.Where(C=>C.CreatedDate==CreatedDate);
如果(ModifiedDate>DateTime.MinValue)limitQuery=limitQuery.Where(C=>C.ModifiedDate==ModifiedDate);
返回查询;
}
#端区
}
当跟踪打开时,选择速度较慢。你绝对应该关闭跟踪并重新测量
看看我的基准
这可能只是一种预感,但是。。。在存储过程中,过滤器定义良好,SP处于编译状态,执行计划合理。您的EF查询将从头构建,并在每次使用时重新编译。因此,现在的任务是设计一种方法,在不同的使用之间编译和保存EF查询。一种方法是重写FilterQuery,使其不依赖于fluent条件方法链。不要在每次参数集更改时附加或不附加新条件,而是将其转换为一个条件,当满足条件时应用过滤器,否则将被1.Equals(1)之类的内容覆盖。这样,您的查询就可以被遵从,并可供重复使用。支持的SQL看起来很时髦,但执行时间应该会提高。或者,您可以设计面向方面的编程方法,其中编译的查询将根据参数值重新使用。如果我有时间,我会在Code Project上发布一个示例。谢谢您的回复。我尝试将
.AsNoTracking()
添加到ctxt.CoverageLimit中的C中的var limitquery=中,虽然我确实看到性能下降到46秒(POCO)而不是7秒(存储过程),但这并不是很显著。不幸的是,除非我能使时间接近可比性,否则我无法接受这一变化。我一直使用SqlConnection/SqlCommand/SqlDataReader专门实现高性能,我更喜欢编写自己的TSQL查询,而不是使用LINQ。我发现我可以简化代码而不牺牲