존재하지 않는 경우 동시에 삽입


13

저장 프로 시저의 삽입에 동시성 문제가 있습니다. 절차의 관련 부분은 다음과 같습니다.

select @_id = Id from table1 where othervalue = @_othervalue
IF( @_id IS NULL)
BEGIN
    insert into table1 (othervalue) values (@_othervalue)
    select @_id = Id from table1 where othervalue = @_othervalue
END

이러한 저장 프로 시저 중 3 또는 4를 동시에 실행하면 경우에 따라 여러 개의 삽입이 발생합니다.

나는 이것을 이렇게 고칠 계획이다.

insert into table1 (othervalue) 
    select TOP(1) @_othervalue as othervalue from table1 WITH(UPDLOCK) 
    where NOT EXISTS ( select * from table1 where othervalue = @_othervalue )

select @_id = Id from table1 where othervalue = @_othervalue

문제는 SQL 서버에서 중복없이 동시에 삽입하는 방법입니까? 한 번만 삽입하기 위해 TOP을 사용해야한다는 사실이 저를 방해합니다.


1
TOP을 사용할 필요는 없습니다. SELECT 문에서 FROM 테이블 참조를 제거하십시오.
ErikE


@ GSerg 나는 당신이 맞다고 생각합니다.
Chris

답변:


7

serializable힌트 와 함께 merge 문을 사용할 수 있습니다 .

merge table1 with (serializable) as T 
using (select @_othervalue as othervalue) as S
on T.othervalue = S.othervalue
when not matched then
  insert (othervalue) values (othervalue);

두 개 이상의 연결에서 접근 방법을 스트레스 테스트 했습니까?
AK

2
@AlexKuznetsov-나는 SO에 대한 또 다른 질문을 위해 얼마 전에 그것을했다. SSMS에서 두 개의 탭을 사용했습니다. 먼저 insert ... where not exist ...패턴을 테스트 한 후 교착 상태 및 키 위반이 발생할 수 있으므로 updlock 및 serializable을 사용해야 함을 발견했습니다. 그런 다음 merge 문을 테스트하고 조금 더 잘 처리 할 것이라고 생각했으며 교착 상태가 없지만 키 위반이 발생하지 않도록 직렬화 가능을 사용해야했기 때문에 수행했습니다.
Mikael Eriksson

1
이것은 정말 멋진 답변입니다.
Chris Marisic

5

'othervalue'열에서 중복을 원하지 않으면 해당 열에서을 만들어 그렇게 할 수 있습니다 unique constraint. 쿼리는 다음과 같습니다.

 ALTER TABLE table1
 ADD CONSTRAINT unique_c_othervalue UNIQUE(othervalue)

쿼리에서 'othervalue'열에 중복 값을 삽입하려고하면 오류가 발생합니다.


고유 제약 조건이 두 행 튜플이면 어떻게 작동합니까?
Chris

1
@Chris 행에 걸친 고유 제약 조건은 어떻게 있습니까?
Aaron Bertrand

@Aaron 아마 내 용어가 꺼져있을 것입니다.하지만 고유 해야하는 두 개의 행이 있습니다. 나는 그것이 우리 스키마에서 시행되지 않는다고 생각합니다.
Chris

2

@StanleyJohns가 권장하는 고유 제한 조건을 사용하십시오. 그런 다음 삽입 문 주위에 BEGIN TRY END TRY를 사용하십시오.

select @_id = Id from table1 where othervalue = @_othervalue
IF( @_id IS NULL)
BEGIN
    BEGIN TRY
        insert into table1 (othervalue) values (@_othervalue)
        select @_id = Id from table1 where othervalue = @_othervalue        
    END TRY
    BEGIN CATCH
        select @_id = Id from table1 where othervalue = @_othervalue        
    END CATCH
END
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.