2013-06-11 3 views
0

이 질문은 Occasionally Getting SqlException: Timeout expired과 관련이 있습니다. 사실, 내 애플 리케이션에 크게 IF EXISTS... UPDATE .. ELSE .. INSERT을 사용하고 있습니다. 그러나 사용자 Remus Rusanu는 이것을 사용해서는 안된다고 말하고 있습니다. 왜 내가 이것을 사용해서는 안되며 위험을 포함시켜야한다. 그렇다면, 내가 가진 경우'존재하는 경우 ... 업데이트 ... ELSE .. INSERT'를 사용하는 위험 및 대안은 무엇입니까?

IF EXISTS (SELECT * FROM Table1 WHERE Column1='SomeValue') 
    UPDATE Table1 SET (...) WHERE Column1='SomeValue' 
ELSE 
    INSERT INTO Table1 VALUES (...) 

이 문장을 다시 작성하여 작동되게하려면 어떻게해야합니까? 2 개 동시 중복과 매우 가까운 전화가 모두 INSERT가 발생하기 전에 존재에서 "false"를 얻을 수 있기 때문에

+1

http://blog.sqlauthority.com/2008/08/28/sql-server-2008-introduction-to-merge-statement-one -statement-for-insert-update-delete/ –

답변

1

문제를 추가하기 전에 적용 동시성에서 다중 스레드 (거래)가 IF EXISTS 부분 를 실행하는 것입니다 모두는 동일한 결론 인에 도달하고 (예 : 존재하지 않음) 그에 따라 행동하십시오. 결과적으로 모든 스레드가 INSERT를 시도하여 키 위반이 발생합니다. 코드에 따라 제약 조건 위반 오류, 교착 상태, 시간 초과 또는 악화 (업데이트 손실)가 발생할 수 있습니다.

IF EXISTS과 그 조치가 원자 적인지 확인해야합니다. SQL Server 2008 이전 버전의 솔루션은 트랜잭션 및 잠금 힌트 사용과 관련되어 매우 오류가 발생하기 쉽습니다 (잘못되기 쉽습니다). SQL Server 2008을 게시하면 MERGE을 사용할 수 있습니다. 그러면 단일 성명과 엔진에서 수행하려는 작업을 이해할 수 있습니다.

+0

MERGE는 원 자성을 보장하기 위해 잠금이 필요합니다. 참조 : http://weblogs.sqlteam.com/dang/archive/2009/01/31/UPSERT-Race-Condition-With-MERGE.aspx –

+0

@ SørenBoisen 당신이 정확하게 내 게시물에서 내가 머지가하는 부분을 지적 할 수 있습니까? 자물쇠가 필요하지 않니? –

+0

@RemusRusanu 그게 문제 야. MERGE가이를 수행하기 위해 잠금 힌트가 절대적으로 필요하다는 언급없이 적절한 원 자성을 보장한다고 간단히 말하면됩니다. –

1

병합은 첫 번째 경우에 2 개의 테이블을 비교하기 위해 만들어 졌으므로 병합을 사용할 수 있습니다.

또 다른 옵션 인 다음을 살펴보십시오.

이 경우 불행히도 동시성에 문제가 발생할 가능성이 있습니다.

--Just update a row 
UPDATE Table1 SET (...) WHERE Column1='SomeValue' 
    -- If 0 rows are updated ... 
    IF @@ROWCOUNT=0 
--Insert Row 
INSERT INTO Table1 VALUES (...) 

this 블로그에서 자세히 설명했습니다.

또한 this interesting blog은 거의 동시성입니다. 이 경우

+1

동시성이 실패합니다. MERGE를 사용하십시오. –

+0

내 게시물을 수정했습니다. 감사합니다. 처음에 나는 또한 Merge를 사용하도록 가르쳤고, 다른 옵션을 먼저 확인했습니다. –

+1

HOLDLOCK 힌트를 사용하지 않으면 MERGE도 동시성에서 실패합니다. http://weblogs.sqlteam.com/dang/archive/2009/01/31/ UPSERT- 레이스 조건 - MERGE.aspx 사용 –

1

샘플 MERGE 문은 다음과 같습니다

MERGE INTO Table1 t1 
USING (SELECT 'SomeValue' as Column_id FROM dual) t2 ON 
(t1.column_id = t2.column_id) 
WHEN MATCHED THEN 
    UPDATE SET(...) 
WHEN NOT MATCHED THEN 
    INSERT (t1.column_id) 
    VALUES ('SomeValue'); 
관련 문제