首页 > 代码库 > SQl server 关于重复插入数据的测试

SQl server 关于重复插入数据的测试

最近发布的脚本,有那种防止重复插入数据(包括存在时更新,不存在是插入的处理,判断的方向可能与下面的示例相反)

使用类似下面的 SQL

declare @id int, @value int

if not exists( select * from tb where id = @id )

    insert tb values( @id, @value );

--else

--  update tb set value = http://www.mamicode.com/@value where id = @id;

 

或者是使用这种单句的

declare @id int, @value int

insert tb select @id, @value

where not exists( select * from tb where id = @id )

--if @@rowcount = 0

--  update tb set value = http://www.mamicode.com/@value where id = @id;

 

或者是用 MERGE 的

declare @id int, @value int

merge tb

    using( values(@id, @value) ) data( id, value)

        on data.id = tb.id

    when not matched by target then insert values( id, value )

    --when matched then update set value = http://www.mamicode.com/data.value

;

         这几种方法均已说明是无法防止插入重复数据的,只是发生的概率高低有一定的区别而已

 

 

针对这种处理需求,我专门做了一些测试,有效的处理方法如下,大家在处理这类问题时,请参考此方法进行:

declare @id int, @value int

begin tran  -- 使查询的更新锁保留到事务结束

if not exists( select * from tb with(holdlock, updlock) where id = @id )

    insert tb values( @id, @value );

--else

--  update tb set value = http://www.mamicode.com/@value where id = @id;

commit tran

 

推荐使用这种单句的处理方式,不用显式的事务控制,避免考虑与其他会显式使用事务的地方的交互性

declare @id int, @value int

insert tb select @id, @value

where not exists( select * from tb with(holdlock, updlock) where id = @id )

--if @@rowcount = 0

--  update tb set value = http://www.mamicode.com/@value where id = @id;

 

不推荐这种方式,容易出来死锁

declare @id int, @value int

merge tb with(holdlock, updlock)

    using( values(@id, @value) ) data( id, value)

        on data.id = tb.id

    when not matched by target then insert values( id, value )

    --when matched then update set value = http://www.mamicode.com/data.value

 

另外,where 这个判断是否重复的条件列,需要创建索引,否则因为锁的关系,数据处理的效率会极低

         如果表中本来就没有重复数据,应该直接建立唯一索引(UNIQUE INDEX),这个对于查询优化有很大的帮助

 

SQl server 关于重复插入数据的测试