SQL Server MERGE命令重复pk错误

如果事务同时发生,此存储过程通常会失败,因为它违反了重复键(字段,名称)上的pk约束。 我一直在尝试,holdlock,rowlock和开始/提交事务,这会导致相同的错误。

我试图执行插入语句,如果记录存在与相同的键(字段,名称)更新它。

性能很重要,所以我试图避免临时表解决方案。

MERGE Fielddata AS TARGET
USING (VALUES (@Field, @Name, @Value, @File, @Type))
    AS SOURCE (Field, Name, Value, File, Type)
    ON TARGET.Field = @Field AND TARGET.Name = @Name
WHEN MATCHED THEN
    UPDATE
    SET Value = SOURCE.Value,
        File = SOURCE.File,
        Type = SOURCE.Type
WHEN NOT MATCHED THEN
    INSERT (Field, Name, Value, File, Type)
    VALUES (SOURCE.Field, SOURCE.Name, SOURCE.Value, SOURCE.File, SOURCE.Type);

编辑:用serializable / holdlock测试24小时。 30分钟后:没有错误。

编辑2: WITH (SERIALIZABLE) / SET TRANSACTION ISOLATION LEVEL SERIALIZABLE可以有效地解决重复的关键问题,在我们的案例/方案中可以节省一点性能。


您必须提高事务隔离级别。 SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

SERIALIZABLE指定以下内容:+语句不能读取已被修改但尚未由其他事务处理的数据。 在当前事务完成之前,没有其他事务可以修改当前事务读取的数据。 其他事务不能插入具有键值的新行,这些键值落在当前事务中任何语句读取的键的范围内,直到当前事务完成。 范围锁放置在与事务中执行的每个语句的搜索条件相匹配的键值范围内。 这会阻止其他事务更新或插入任何符合当前事务执行的任何语句的行。 这意味着如果事务中的任何语句再次执行,它们将读取相同的一组行。 范围锁定一直持续到事务完成。 这是隔离级别最严格的原因,因为它锁定了整个键的范围并持有锁直到事务完成。 由于并发性较低,因此仅在必要时才使用此选项。 此选项与在事务中的所有SELECT语句的所有表上设置HOLDLOCK的效果相同。

可串行化的实现

SQL Server恰巧使用可序列化隔离级别的锁定实现,其中获取物理锁并将其保存到事务的末尾(因此,不建议使用的表提示HOLDLOCK作为SERIALIZABLE的同义词)。

这种策略不足以提供完全可串行化的技术保证,因为新的或更改的数据可能出现在先前由事务处理的一系列行中。 这种并发现象被称为幻影,并且可能导致在任何连续时间表中不可能发生的效果。

为确保防止幻影并发现象发生,SQL Server在可序列化隔离级别执行的锁定还可能包含键范围锁定,以防止在先前检查的索引键值之间出现新的或更改的行。 范围锁不总是在可序列化的隔离级别下获取; 我们所能说的一般情况是SQL Server始终获得足够的锁以满足可序列化隔离级别的逻辑要求。 实际上,锁定实现通常会获得比确保可串行化真正需要更多,更严格的锁定,但我离题了。

https://sqlperformance.com/2014/04/t-sql-queries/the-serializable-isolation-level

如果它很简单:它不仅阻止源,而且阻止插入的范围

链接地址: http://www.djcxy.com/p/32883.html

上一篇: SQL Server MERGE command duplicate pk error

下一篇: SQL Server insert locking with concurrent transactions