0

I have several unique indexes. For example

SET ansi_nulls ON 

go 

SET quoted_identifier ON 

go 

CREATE TABLE [dbo].[tblrelatedwords] 
  ( 
     [cl_orgwordid]           [BIGINT] NOT NULL, 
     [cl_relatedwordid]       [BIGINT] NOT NULL, 
     [cl_relatedwordtypecode] [SMALLINT] NOT NULL, 
     [cl_relation_sourceid]   [TINYINT] NOT NULL, 
     CONSTRAINT [PK_tblSeeAlso] PRIMARY KEY CLUSTERED ( [cl_orgwordid] ASC, 
     [cl_relatedwordid] ASC, [cl_relatedwordtypecode] ASC )WITH (pad_index = OFF 
     , statistics_norecompute = OFF, ignore_dup_key = OFF, allow_row_locks = on, 
     allow_page_locks = on, FILLFACTOR = 90) ON [PRIMARY] 
  ) 
ON [PRIMARY] 

go 

ALTER TABLE [dbo].[tblrelatedwords] 
  ADD CONSTRAINT [DF_tblSeeAlso_cl_RelatedWordTypeCode] DEFAULT ((255)) FOR 
  [cl_RelatedWordTypeCode] 

go 

When i use below query systematic even though i check with If not exists, i am still getting the below error

IF NOT EXISTS
  ( SELECT 1
   FROM tblRelatedWords
   WHERE (cl_OrgWordId=@cl_OrgWordId
          AND cl_RelatedWordId=@cl_RelatedWordId
          AND cl_RelatedWordTypeCode=@cl_RelatedWordTypeCode)
     OR (cl_OrgWordId=@cl_RelatedWordId
         AND cl_RelatedWordId=@cl_OrgWordId
         AND cl_RelatedWordTypeCode=@cl_RelatedWordTypeCode) ) BEGIN
INSERT INTO tblRelatedWords
VALUES (@cl_OrgWordId,
        @cl_RelatedWordId,
        @cl_RelatedWordTypeCode,
        @cl_Relation_SourceId) END

Error

Violation of PRIMARY KEY constraint 'PK_tblSeeAlso'. Cannot insert duplicate key in object 'dbo.tblRelatedWords'. The duplicate key value is (11439364, 2495501, 243).  The statement has been terminated.

Yes multiple threads are adding to the same table however aren't IF NOT EXISTS supposed to prevent such cases?

Microsoft SQL Server 2016 (SP1-CU2) (KB4013106) - 13.0.4422.0 (X64)

Furkan Gözükara
  • 22,964
  • 77
  • 205
  • 342
  • What transaction isolation level are you using for your queries? What's the default for the database? – alroc May 09 '17 at 11:20
  • You can use `merge` statement. Or you can enclose your batch into transaction and use `with (updlock)` hint in `if exists(select ...` part of your query. – Arvo May 09 '17 at 11:24
  • 1
    The `NOT EXISTS` and the `INSERT` are two separate operations and therefore there is a gap between them in which the same record can be inserted. For more information on race conditions in SQL Server [this is quite informative](http://weblogs.sqlteam.com/dang/archive/2007/10/28/Conditional-INSERTUPDATE-Race-Condition.aspx), and as far as I know, the best thread safe solution is to use `MERGE .. WITH (HOLDLOCK)` as discussed [in this article](http://weblogs.sqlteam.com/dang/archive/2009/01/31/UPSERT-Race-Condition-With-MERGE.aspx). – GarethD May 09 '17 at 11:26
  • @alroc whatever the default is – Furkan Gözükara May 09 '17 at 11:30
  • @Arvo can you post your updlock answer – Furkan Gözükara May 09 '17 at 11:30
  • @GarethD yes i also thought about gap and it makes sense. however it seems like merge still can cause inconsistency according to the article you have pointed – Furkan Gözükara May 09 '17 at 11:31
  • ah i guess best approach is modifying select statement with WITH (UPDLOCK, HOLDLOCK) right? – Furkan Gözükara May 09 '17 at 11:32
  • Is serializable the default for SQL Server? – McMurphy May 09 '17 at 11:50
  • @McMurphy nope not always positive, it may exists or may not exists – Furkan Gözükara May 09 '17 at 11:50
  • Does the error occur at VERB time or COMMIT time? Commit-time evaluation of constraints and more thatn 1 insert? i.e. in a loop? – McMurphy May 09 '17 at 11:53
  • @McMurphy i dont know. i have found from the logs that it has failed with the error i have posted. can you also check this question? http://stackoverflow.com/questions/43869042/preventing-conditional-insert-update-race-condition-in-ms-sql – Furkan Gözükara May 09 '17 at 11:54
  • Apparently SQL Server now supports deferable constraints. (Needed if Table A has a FK to Table B and vice versa) Anyway not the default so if you can't find "defer" in your code or stored procedures then it's probably irrelevant. – McMurphy May 09 '17 at 12:05
  • @McMurphy yes i dont have any defer. the question contains full table details and the query details – Furkan Gözükara May 09 '17 at 12:08

0 Answers0