- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我在 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 管理工作室:
执行时间 <1 秒。
好吧,这很奇怪!?
一些测试:
首先,我比较了两个执行计划( Entity Framework 和 SSMS),但它们完全相同。
我尝试的第二个是在我的代码中使用事务。
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 秒。性能仍然很差。
问题:我做错了什么?请给我一个提示。
如果我在事务中执行命令(如上),会出现以下时间:
持续时间完成: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/
有没有办法在 EF 中使用 ExecuteStoreCommand 执行多个插入语句?我正在使用 StringBuilder 生成多个插入语句。代码基本上是这样的 StringBuilder _sav
我在这里做错了什么? ... using (var ctx = ObjectContextManager.GetManager("MyDataContext")) { var idsToUpd
我使用不同的命令和不同的参数多次调用 ObjectContext.ExecuteStoreCommand,尽管我对几个命令使用相同的参数列表(对象)。我收到以下异常: System.ArgumentE
我在 Entity Framework 6 上执行简单的合并 SQL 命令时遇到了一个奇怪的性能问题。 首先是我的 Entity Framework 代码: var command = @"MERGE
在entityframework中我们可以使用ExecuteStoreQuery或者ExecuteStoreCommand来执行sql查询。那么它们之间有什么区别(不同的场景)? 谢谢。 最佳答案 M
我想获得下一个自动递增的主键,Here我明白要使用 T-SQL 来做到这一点。所以我写了下面的方法: public int GetLastNewsID() { const string com
在针对 SQL Server 2008 数据库运行的 C# 程序中,从 SQL Server View 中选择字段的特定 LINQ-to-SQL 查询在我的本地开发环境中运行良好,但在暂存环境中运行时
我在 VS2012 中使用 EF5,我尝试使用 ExecuteStoreCommand 删除某个表的所有数据,像这样: ctx.ExecuteStoreCommand("TRUNCATE TABLE
我在 Azure sql db 中有一个存储过程,当我从 SSMS 运行时,它在大约 300 毫秒内完成。 sproc 接受一个 id 和一个日期范围,收集一些数据并将其保存到聚合表中。 它不返回任何
在直接调用存储过程或函数时,我尝试将 SQL Server 命名参数与 ObjectContext.ExecuteStoreQuery 和 ObjectContext.ExecuteStoreComm
以下有什么区别- CreateQuery() ExecuteFunction(), ExecuteStoreQuery() and ExecuteStoreCommand() 据我所知,Create
我是一名优秀的程序员,十分优秀!