gpt4 book ai didi

c# - ExecuteStoreCommand 上出现奇怪的 EF6 性能问题

转载 作者:太空宇宙 更新时间:2023-11-03 23:07:25 33 4
gpt4 key购买 nike

我在 Entity Framework 6 上执行简单的合并 SQL 命令时遇到了一个奇怪的性能问题。

首先是我的 Entity Framework 代码:

var command = @"MERGE [StringData] AS TARGET
USING (VALUES (@DCStringID_Value, @TimeStamp_Value)) AS SOURCE ([DCStringID], [TimeStamp])
ON TARGET.[DCStringID] = SOURCE.[DCStringID] AND TARGET.[TimeStamp] = SOURCE.[TimeStamp]
WHEN MATCHED THEN
UPDATE
SET [DCVoltage] = @DCVoltage_Value,
[DCCurrent] = @DCCurrent_Value
WHEN NOT MATCHED THEN
INSERT ([DCStringID], [TimeStamp], [DCVoltage], [DCCurrent])
VALUES (@DCStringID_Value, @TimeStamp_Value, @DCVoltage_Value, @DCCurrent_Value);";

using (EntityModel context = new EntityModel())
{
for (int i = 0; i < 100; i++)
{
var entity = _buffer.Dequeue();

context.ContextAdapter.ObjectContext.ExecuteStoreCommand(command, new object[]
{
new SqlParameter("@DCStringID_Value", entity.DCStringID),
new SqlParameter("@TimeStamp_Value", entity.TimeStamp),
new SqlParameter("@DCVoltage_Value", entity.DCVoltage),
new SqlParameter("@DCCurrent_Value", entity.DCCurrent),
});
}
}

执行时间~20 秒

这看起来有点慢,所以我尝试在管理工作室中直接运行相同的命令(也是连续 100 次)。

SQL Server 管理工作室:

editor

执行时间 <1 秒

好吧,这很奇怪!?

一些测试:

首先,我比较了两个执行计划( Entity Framework 和 SSMS),但它们完全相同。

enter image description here

我尝试的第二个是在我的代码中使用事务。

using (PowerdooModel context = PowerdooModel.CreateModel())
{
using (var dbContextTransaction = context.Database.BeginTransaction())
{
try
{
for (int i = 0; i < 100; i++)
{
context.ContextAdapter.ObjectContext.ExecuteStoreCommand(command, new object[]
{
new SqlParameter("@DCStringID_Value", entity.DCStringID),
new SqlParameter("@TimeStamp_Value", entity.TimeStamp),
new SqlParameter("@DCVoltage_Value", entity.DCVoltage),
new SqlParameter("@DCCurrent_Value", entity.DCCurrent),
});
}

dbContextTransaction.Commit();
}
catch (Exception)
{
dbContextTransaction.Rollback();
}
}
}

第三,我添加了“选项(重新编译)”以避免参数嗅探。

执行时间仍然是 ~10 秒。性能仍然很差。

问题:我做错了什么?请给我一个提示。

-------- 一些更多的测试 - 2016 年 11 月 18 日编辑 ----------

如果我在事务中执行命令(如上),会出现以下时间:

持续时间完成:00:00:06.5936006

平均命令:00:00:00.0653457

提交:00:00:00.0590299

提交几乎不需要时间,而平均命令花费的时间几乎相同,这不奇怪吗?

最佳答案

在 SSMS 中,您正在运行一个长批处理,其中包含 100 个单独的 MERGE 语句。在 C# 中,您正在运行 100 个单独的批处理。显然它更长。

在 100 个单独事务中运行 100 个单独批处理显然比在 1 个事务中运行 100 个批处理要长。您的测量结果证实了这一点,并告诉您还有多长时间。


为了提高效率,使用单个 MERGE 语句来处理 table-valued parameter 中的所有 100 行。一气呵成。另见 Table-Valued Parameters for .NET Framework

表值参数通常是存储过程的参数,但您不一定非要使用存储过程。它可以是单个语句,但不是多个简单的标量参数,而是一次传递整个表。

我从未使用过 Entity Framework ,因此无法向您展示如何调用它的 C# 示例。我敢肯定,如果您搜索“如何在 Entity Framework 中传递表值参数”,您会找到一个示例。我使用 DataTable 类将表作为参数传递。

我可以向您展示一个 T-SQL 存储过程的示例。

首先,您定义一个表类型,它几乎遵循您的 StringData 表的定义:

CREATE TYPE dbo.StringDataTableType AS TABLE(
DCStringID int NOT NULL,
TimeStamp datetime2(0) NOT NULL,
DCVoltage float NOT NULL,
DCCurrent float NOT NULL
)

然后将其用作参数的类型:

CREATE PROCEDURE dbo.MergeStringData
@ParamRows dbo.StringDataTableType READONLY
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;

BEGIN TRANSACTION;
BEGIN TRY

MERGE INTO dbo.StringData WITH (HOLDLOCK) as Dst
USING
(
SELECT
TT.DCStringID
,TT.TimeStamp
,TT.DCVoltage
,TT.DCCurrent
FROM
@ParamRows AS TT
) AS Src
ON
Dst.DCStringID = Src.DCStringID AND
Dst.TimeStamp = Src.TimeStamp
WHEN MATCHED THEN
UPDATE SET
Dst.DCVoltage = Src.DCVoltage
,Dst.DCCurrent = Src.DCCurrent
WHEN NOT MATCHED BY TARGET THEN
INSERT
(DCStringID
,TimeStamp
,DCVoltage
,DCCurrent)
VALUES
(Src.DCStringID
,Src.TimeStamp
,Src.DCVoltage
,Src.DCCurrent)
;

COMMIT TRANSACTION;
END TRY
BEGIN CATCH
-- TODO: handle the error
ROLLBACK TRANSACTION;
END CATCH;
END

同样,它不必是一个存储过程,它可以只是一个带有一个表值参数的 MERGE 语句。

我很确定它会比您使用 100 个单独查询的循环快得多。

关于为什么应该有 HOLDLOCK 提示和 MERGE 的详细信息:“UPSERT” Race Condition With MERGE


旁注:上次测试中的 Commit 非常快并不奇怪。它没什么用,因为所有内容都已写入数据库。如果您尝试执行 Rollback,那将需要一些时间。

关于c# - ExecuteStoreCommand 上出现奇怪的 EF6 性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40688147/

33 4 0
文章推荐: 没有文本的元素的 CSS 伪类
文章推荐: python - 使用 Python(点阵 OCR)从图像中提取文本时获取不正确的文本
文章推荐: javascript - 为
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com