JK.*_*JK. 9 c# sql-server performance entity-framework objectcontext
我为这个问题缺乏细节而道歉 - 我需要帮助的第一件事就是知道在哪里寻找更多细节.
我有一个enity框架4导航属性的问题,显然在提交更改时导致性能不佳:
this.ObjectContext.SaveChanges();
Run Code Online (Sandbox Code Playgroud)
当其中一个导航属性(收据表)包含大约8000行(这不是很多,所以应该没问题)时,需要30多秒.
我使用过SQL分析器,可以看到EF从Receipts发出select*并且它非常慢:
exec sp_executesql N'SELECT
[Extent1].[Id] AS [Id],
// full field list cut for brevity
FROM [dbo].[Receipts] AS [Extent1]
WHERE [Extent1].[WarehouseId] = @EntityKeyValue1',
N'@EntityKeyValue1 int',@EntityKeyValue1=1
Run Code Online (Sandbox Code Playgroud)
目前,当调用ObjectContext.SaveChanges()时,我甚至无法理解为什么需要从该表中选择所有行.
它确实需要在此表中插入1行,但这并不能解释为什么它首先执行select - 并且不能解释为什么select会花费这么长时间(同一查询在查询管理器中占用<1秒)
所以我现在的问题 - 我还不知道问题是什么 - 是:
编辑:
我已经通过注释掉对此方法的调用来确认收据代码很慢:
private void AddReceipt(PurchaseInvoice invoice,
PurchaseInvoiceLine invoiceLine)
{
if (invoice != null && invoiceLine != null)
{
Product product = invoiceLine.Product;
if (product != null)
{
Receipt receipt = new Receipt{ foo = bar };
WarehouseDetail detail = new WarehouseDetail{ foo = bar };
receipt.WarehouseDetails.Add(detail);
invoice.Receipts.Add(receipt);
}
}
}
Run Code Online (Sandbox Code Playgroud)
但我仍然无法理解为什么这会导致EF发出select*查询.
我相信它可能是由于引起的延迟加载问题invoice.Receipts.Add(receipt)
.因为在该行之前invoice.Receipts为空,并且为了添加到收据,它必须首先加载集合.但这并不能解释为什么它应该由warehouseId = 1选择,何时应该由invoiceId选择.
编辑2:
我通过使用直接SQL命令替换此方法中的EF代码来"修复"该问题.这不是一个好主意 - 当我有一个非常好的ORM时,我不应该抛出SQL.但是现在我仍然不明白为什么EF运行select*查询
private void AddReceipt(PurchaseInvoice invoice,
PurchaseInvoiceLine invoiceLine)
{
if (invoice != null && invoiceLine != null)
{
Product product = invoiceLine.Product;
if (product != null)
{
Receipt receipt = new Receipt{ foo = bar };
WarehouseDetail detail = new WarehouseDetail{ foo = bar };
int id = SqlHelper.AddWarehouseDetail(detail);
receipt.WarehouseDetailId = id;
SqlHelper.AddReceipt(receipt);
}
}
}
Run Code Online (Sandbox Code Playgroud)
由于这是一个插入,因此它会通过选择回值并重新填充对象来刷新您的对象。现在让我回答您提出的问题:
您不应该需要调试而不是SaveChanges()
,您所看到的可能无论如何都没有多大意义。
它实际上并不是在做一个select * from Receipts
. 它正在做一个select * from Receipts where WarehouseId = 1
. 因此,由于某些原因,您反对提取 ID 为 1 的仓库的所有收据。
这可能取决于很多事情,你现在确实无法介入。但一个开始的地方是检查应用程序框和数据库框之间的 ping 速率。还要检查数据库盒上的 RAM 是否已满。这就是我要开始的地方,这也是您所描述的常见问题。
EF Profiler 是调试 EF 的一个好工具。 http://efprof.com 这将比 SQL Profiler 对您有更多帮助。