SQL INSERT but avoid duplicates

前端 未结 6 987
北荒
北荒 2020-12-31 10:42

I want to do some quick inserts but avoid duplicates into a Table. For argument\'s sake lets call it MarketPrices, I\'ve been experimenting with two ways of doing it but not

6条回答
  •  悲&欢浪女
    2020-12-31 11:10

    Below I have added the top answers from Only inserting a row if it's not already there to Peter Radocchia's excellent answer.

    The takeaway is that using the race safe with try/catch technique is marginally (~1%) faster than race safe with updlock, holdlock technique when there are no actual collisions (i.e. you expect that collisions will be very rare - this is the uniques scenario), and is a little slower (~20%) when there are always collisions (this is the duplicates scenario). This is not taking complex issues like lock escalation into account.

    Here are the results (SQL Server 2014, build 12.0.2000.8):

    duplicates (short table)    
      try/catch:                       15546 milliseconds / 100000 inserts
      conditional insert:               1460 milliseconds / 100000 inserts
      except:                           1490 milliseconds / 100000 inserts
      merge:                            1420 milliseconds / 100000 inserts
      race safe with try/catch:         1650 milliseconds / 100000 inserts
      race safe with updlock, holdlock: 1330 milliseconds / 100000 inserts
    
    uniques
      try/catch:                        2266 milliseconds / 100000 inserts
      conditional insert:               2156 milliseconds / 100000 inserts
      except:                           2273 milliseconds / 100000 inserts
      merge:                            2136 milliseconds / 100000 inserts
      race safe with try/catch:         2400 milliseconds / 100000 inserts
      race safe with updlock, holdlock: 2430 milliseconds / 100000 inserts
    
      straight insert:                  1686 milliseconds / 100000 inserts
    
    duplicates (tall table)
      try/catch:                       15826 milliseconds / 100000 inserts
      conditional insert:               1530 milliseconds / 100000 inserts
      except:                           1506 milliseconds / 100000 inserts
      merge:                            1443 milliseconds / 100000 inserts
      race safe with try/catch:         1636 milliseconds / 100000 inserts
      race safe with updlock, holdlock: 1426 milliseconds / 100000 inserts
    

    Duplicates (short table) section:

    declare @x int, @y int, @now datetime, @duration int
    select @x = 1, @y = 0, @now = getdate()
    while @y < 100000 begin
      set @y = @y+1
      begin try 
        insert #temp select @x where not exists (select * from #temp where col1 = @x)
      end try
      begin catch 
        if error_number() <> 2627
          throw
      end catch
    end
    set @duration = datediff(ms,@now,getdate())
    raiserror('duplicates (short table), race safe with try/catch: %i milliseconds / %i inserts',-1,-1,@duration,@y) with nowait
    go
    
    declare @x int, @y int, @now datetime, @duration int
    select @x = 1, @y = 0, @now = getdate()
    while @y < 100000 begin
      set @y = @y+1
      insert #temp select @x where not exists (select * from #temp with (updlock, holdlock) where col1 = @x)
    end
    set @duration = datediff(ms,@now,getdate())
    raiserror('duplicates (short table), race safe with updlock, holdlock: %i milliseconds / %i inserts',-1,-1,@duration, @y) with nowait
    go
    

    Uniques section

    truncate table #temp
    declare @x int, @now datetime, @duration int
    select @x = 0, @now = getdate()
    while @x < 100000 begin
      set @x = @x+1
      begin try 
        insert #temp select @x where not exists (select * from #temp where col1 = @x)
      end try
      begin catch 
        if error_number() <> 2627
          throw
      end catch
    end
    set @duration = datediff(ms,@now,getdate())
    raiserror('uniques, race safe with try/catch: %i milliseconds / %i inserts',-1,-1,@duration, @x) with nowait
    go
    
    truncate table #temp
    declare @x int, @now datetime, @duration int
    select @x = 0, @now = getdate()
    while @x < 100000 begin
      set @x = @x+1
      insert #temp select @x where not exists (select * from #temp with (updlock, holdlock) where col1 = @x)
    end
    set @duration = datediff(ms,@now,getdate())
    raiserror('uniques, race safe with updlock, holdlock: %i milliseconds / %i inserts',-1,-1,@duration, @x) with nowait
    go
    

    Duplicates (tall table) section

    declare @x int, @y int, @now datetime, @duration int
    select @x = 1, @y = 0, @now = getdate()
    while @y < 100000 begin
      set @y = @y+1
      begin try 
        insert #temp select @x where not exists (select * from #temp where col1 = @x)
      end try
      begin catch 
        if error_number() <> 2627
          throw
      end catch
    end
    set @duration = datediff(ms,@now,getdate())
    raiserror('duplicates (tall table), race safe with try/catch: %i milliseconds / %i inserts',-1,-1,@duration,@y) with nowait
    go
    
    declare @x int, @y int, @now datetime, @duration int
    select @x = 1, @y = 0, @now = getdate()
    while @y < 100000 begin
      set @y = @y+1
      insert #temp select @x where not exists (select * from #temp with (updlock, holdlock) where col1 = @x)
    end
    set @duration = datediff(ms,@now,getdate())
    raiserror('duplicates (tall table), race safe with updlock, holdlock: %i milliseconds / %i inserts',-1,-1,@duration, @y) with nowait
    go
    

提交回复
热议问题