ASP.NET MVC 和 EF 多连接缩放
ASP.NET MVC & EF multiple joins scaling
我正在使用 ASP.NET MVC 和 Entity Framework 从单个 API 连接到多个数据库。我目前正在重构一些遗留代码以减轻服务器负载(我们预计在不久的将来会有很大的提升)。
有几个控制器有类似的问题,每次为 return 生成特定对象时都会消耗大量 CPU 电量。目前使用的方法是为每个table创建一个对象,然后从检索到的table中构造一个对象。
像这样:
public IHttpActionResult Get(string code)
{
using (DataEntities entities = new DataEntities())
{
var table1 = entities.Table1.FirstOrDefault(t1 => t1.ItemCode == code);
if (table1 == null)
{
return NotFound();
}
var table2 = entities.Table2.FirstOrDefault(t2 => t2.ItemId == table1.ItemId);
var table3 = entities.Table3.FirstOrDefault(t3 => t3.ItemId == table1.ItemId);
return Ok(new TableValues()
{
ItemCode = code,
Table1Value = table1.Value;
Table2Value = table2.Value;
Table3Value = table3.Value;
});
}
}
class TableValues
{
public string ItemCode;
public int Table1Value;
public int Table2Value;
public int Table3Value;
}
我最近做的优化是从查询中删除额外的数据,并在缺少数据时设置默认值,而只是 select 需要什么,在这个例子中 Table1
有 200 多个字段和我只需要几个,所以这将时间从大约 180 毫秒减少到 10 毫秒:
public IHTTPActionResult Get(string code)
{
using (DataEntities entities = new DataEntities())
{
var table1 = entities.Table1
.FirstOrDefault(t1 => t1.ItemCode == code)
.Select(t1 => new Table1Short()
{
ItemCode = t1.ItemCode,
Value1 = t1.Value1,
Value2 = t1.Value2,
Value3 = t1.Value3
});
if (table1 == null)
{
return NotFound("Not found in database");
}
return Ok(table1);
}
}
class Table1Short
{
public string ItemCode = string.Empty;
public int Value1 = 0;
public int Value2 = 0;
public int Value3 = 0;
}
有没有什么方法可以创建具有多个 table 的 IQueryable
,然后应用 .Select
来使用各种连接的 table 构造对象?
最终结果将如下所示:
public IHttpActionResult Get(string code)
{
using (DataEntities entities = new DataEntities())
{
// THIS LINE WONT WORK AS IS
var tableValuesQuery = entities.Table1
.Join(entities.Table2 as t2)
.Join(entities.Table3 as t3);
table1 = tableValuesQuery.FirstOrDefault((t1, t2, t3) => t1.ItemCode == code)
.Select((t1, t2, t3) => new TableValues()
{
ItemCode = t1.ItemCode
Value1 = t1.Value,
Value2 = t2.Value,
Value3 = t3.Value
});
// ADDITIONAL CODE TO JOIN TABLES HERE AS "t2" and "t3"
if (table1 == null)
{
return NotFound("Not found in database");
}
return Ok(table1);
}
}
class TableValues
{
public int ItemId = string.Empty;
public int Table1Value = 0;
public int Table2Value = 0;
public int Table3Value = 0;
}
这样做会稍微提高速度并防止 API 用户端因丢失数据(不可空数据类型中的空值)而出错。我检查了文档,发现只有 2 个 table 被加入的例子,我似乎无法与 3.
一起正常工作
最后一点:我只想创建一个 SQL 视图并将其导入到 EF 中,但遗憾的是这不是一个选项,因为某些数据库的修改是使用它们的程序所独有的。
感谢“Kirk Wolf”的回答。通过在我的数据模型中添加关联,我能够创建与问题中的第二段代码非常相似的结果。在(较小的)查询和 运行 一些基准测试中执行此操作后,性能似乎从平均 20 毫秒变为平均 5 毫秒。一个非常受欢迎的提升应该转化为更大控制器的更多时间节省。
步骤:
向数据模型添加关联
重新编译
访问对象如下
public IHttpResult Get(string code) {
var result = entities.Table1.Where(t1 => t1.ItemCode == code)
.Select(t1 => new TableValues() {
ItemCode = t1.ItemCode,
Value1 = t1.Value,
Value2 = t1.Table2.Value
Value3 = t1.Table3.Value
})
.FirstOrDefault();
if (result == null) {
return NotFound();
}
return Ok(result);
}
作为最后的说明,这里是我测试的一些细节:
控制器连接了来自 6 个表的数据并对其进行了最少的处理(仅 3 个字段)。
表格共有 487 个字段。
returned字段一共22个,2个在controller中生成,1个在controller中修改。
准备对象 return 的总时间从平均 20 毫秒减少到平均 5 毫秒。
我正在使用 ASP.NET MVC 和 Entity Framework 从单个 API 连接到多个数据库。我目前正在重构一些遗留代码以减轻服务器负载(我们预计在不久的将来会有很大的提升)。
有几个控制器有类似的问题,每次为 return 生成特定对象时都会消耗大量 CPU 电量。目前使用的方法是为每个table创建一个对象,然后从检索到的table中构造一个对象。
像这样:
public IHttpActionResult Get(string code)
{
using (DataEntities entities = new DataEntities())
{
var table1 = entities.Table1.FirstOrDefault(t1 => t1.ItemCode == code);
if (table1 == null)
{
return NotFound();
}
var table2 = entities.Table2.FirstOrDefault(t2 => t2.ItemId == table1.ItemId);
var table3 = entities.Table3.FirstOrDefault(t3 => t3.ItemId == table1.ItemId);
return Ok(new TableValues()
{
ItemCode = code,
Table1Value = table1.Value;
Table2Value = table2.Value;
Table3Value = table3.Value;
});
}
}
class TableValues
{
public string ItemCode;
public int Table1Value;
public int Table2Value;
public int Table3Value;
}
我最近做的优化是从查询中删除额外的数据,并在缺少数据时设置默认值,而只是 select 需要什么,在这个例子中 Table1
有 200 多个字段和我只需要几个,所以这将时间从大约 180 毫秒减少到 10 毫秒:
public IHTTPActionResult Get(string code)
{
using (DataEntities entities = new DataEntities())
{
var table1 = entities.Table1
.FirstOrDefault(t1 => t1.ItemCode == code)
.Select(t1 => new Table1Short()
{
ItemCode = t1.ItemCode,
Value1 = t1.Value1,
Value2 = t1.Value2,
Value3 = t1.Value3
});
if (table1 == null)
{
return NotFound("Not found in database");
}
return Ok(table1);
}
}
class Table1Short
{
public string ItemCode = string.Empty;
public int Value1 = 0;
public int Value2 = 0;
public int Value3 = 0;
}
有没有什么方法可以创建具有多个 table 的 IQueryable
,然后应用 .Select
来使用各种连接的 table 构造对象?
最终结果将如下所示:
public IHttpActionResult Get(string code)
{
using (DataEntities entities = new DataEntities())
{
// THIS LINE WONT WORK AS IS
var tableValuesQuery = entities.Table1
.Join(entities.Table2 as t2)
.Join(entities.Table3 as t3);
table1 = tableValuesQuery.FirstOrDefault((t1, t2, t3) => t1.ItemCode == code)
.Select((t1, t2, t3) => new TableValues()
{
ItemCode = t1.ItemCode
Value1 = t1.Value,
Value2 = t2.Value,
Value3 = t3.Value
});
// ADDITIONAL CODE TO JOIN TABLES HERE AS "t2" and "t3"
if (table1 == null)
{
return NotFound("Not found in database");
}
return Ok(table1);
}
}
class TableValues
{
public int ItemId = string.Empty;
public int Table1Value = 0;
public int Table2Value = 0;
public int Table3Value = 0;
}
这样做会稍微提高速度并防止 API 用户端因丢失数据(不可空数据类型中的空值)而出错。我检查了文档,发现只有 2 个 table 被加入的例子,我似乎无法与 3.
一起正常工作最后一点:我只想创建一个 SQL 视图并将其导入到 EF 中,但遗憾的是这不是一个选项,因为某些数据库的修改是使用它们的程序所独有的。
感谢“Kirk Wolf”的回答。通过在我的数据模型中添加关联,我能够创建与问题中的第二段代码非常相似的结果。在(较小的)查询和 运行 一些基准测试中执行此操作后,性能似乎从平均 20 毫秒变为平均 5 毫秒。一个非常受欢迎的提升应该转化为更大控制器的更多时间节省。 步骤:
向数据模型添加关联
重新编译
访问对象如下
public IHttpResult Get(string code) { var result = entities.Table1.Where(t1 => t1.ItemCode == code) .Select(t1 => new TableValues() { ItemCode = t1.ItemCode, Value1 = t1.Value, Value2 = t1.Table2.Value Value3 = t1.Table3.Value }) .FirstOrDefault(); if (result == null) { return NotFound(); } return Ok(result); }
作为最后的说明,这里是我测试的一些细节:
控制器连接了来自 6 个表的数据并对其进行了最少的处理(仅 3 个字段)。
表格共有 487 个字段。
returned字段一共22个,2个在controller中生成,1个在controller中修改。
准备对象 return 的总时间从平均 20 毫秒减少到平均 5 毫秒。