我的应用程序中有一个ADO.Net数据访问层,它使用基本的ADO.Net和CRUD存储过程(每个操作一个,例如Select_myTable,Insert_myTable)。可以想象,在大型系统(如我们的系统)中,DA层所需的DB对象数量非常大。
我一直在研究将层类重构为EF POCO类的可能性。我已经设法做到这一点,但是当我尝试进行性能测试时,它变得非常可怕。使用下面的类(创建对象,将Key设置为所需的值,调用dataselect),100000次数据加载仅需要大约47秒(数据库中只有少数记录)。而Stored Proc方法大约需要7秒钟。
我正在寻找关于如何优化这一点的建议 - 作为一个注意事项,我不能改变层的暴露功能 - 只是它如何实现方法(即我不能将上下文所有权的责任转交给BO层)
由于
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
}
答案 0 :(得分:1)
跟踪时选择很慢。你绝对应该关闭跟踪并再次测量。
看看我的基准
http://netpl.blogspot.com/2013/05/yet-another-orm-micro-benchmark-part-23_15.html
答案 1 :(得分:0)
这可能只是一种预感,但是......在您的存储过程中,过滤器定义良好,SP处于编译状态,具有良好的执行计划。您的EF查询从头开始构建,并在每次使用时重新编译。因此,现在的任务就是设计一种在使用之间编译和保存EF查询的方法。一种方法是重写您的FilterQuery以不依赖于流畅的条件方法链。每次参数集更改时,不是追加或不附加新条件,而是将其转换为一个,其中过滤器在满足条件时应用,或者在没有时被1.Equals(1)覆盖。这样您的查询就可以被编译并可以重复使用。支持SQL看起来很时髦,但执行时间应该会有所改善。或者,您可以设计面向方面编程方法,其中编译查询将根据参数值重新使用。如果我有时间,我会在Code Project上发布一个样本。