CREATE TABLE 잠금


19

다른 응용 프로그램에서 나는 나쁜 디자인에 감동했습니다 : 여러 스레드가 EnsureDatabaseSchemaExists()동시에 메소드를 실행합니다. 기본적으로 다음과 같습니다.

IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'MyTable') AND type = N'U') BEGIN

    CREATE TABLE MyTable ( ... );

END

그러나 SERIALIZABLE 트랜잭션에서 실행 되더라도이 코드는 스레드 안전하지 않은 것 같습니다 (예 : 병렬 코드는 테이블을 여러 번 작성하려고 시도 함). 다른 스레드가 동일한 SELECT 문을 수행하지 못하게하는 SELECT 문을 강제로 잠금을 획득 할 수있는 기회가 있습니까?

멀티 스레드 EnsureSchemaExists () 메소드에 더 좋은 패턴이 있습니까?

답변:


18

sp_getapplock을 사용하여 전체 작업 ( SELECTCREATE TABLE) 을 보호하기 위해 명시 적 포함 트랜잭션을 사용하고 사용자 지정 배타적 잠금을 얻는 것이 가장 좋습니다 . 시스템 개체는 격리 수준 요청을 따르지 않으며 사용자 테이블과 같은 방식으로 잠금을 사용합니다.

원래 코드의 경쟁 조건은 스레드가 CREATE TABLE명령문 까지 도달하기 전에 여러 스레드가 테이블이 존재하지 않는다는 결론을 내릴 수 있다는 것 입니다.


6
+1은 applock 이 SELECT 검사를 래핑하는지 확인하십시오 . 그렇지 않으면 교착 상태가 발생합니다. 이상적으로는 S 모드에서 앱 잠금을 얻고 X 로의 업그레이드를 확인하지만 까다 롭습니다 (최소한 ...). 가장 안전한 옵션은 X를 획득 한 다음 전체 DB 스키마 배포를 수행하는 것입니다. X 잠금은 그다지 중요하지 않으므로 드문 op (예 : 앱 시작시) 여야합니다.
Remus Rusanu

12

최선의 노력을 다하는 것이 좋습니다. 예를 들어, 중복 사례를 명시 적으로 처리하십시오. 무시해...

실제 질문 : DDL이 여러 xact에서 주문형으로 실행되는 이유는 무엇입니까? 일반적으로 업그레이드 및 마이그레이션은 심각한 문제이며 전용 시간 창에서 처리됩니다. 마이그레이션 (코드 우선)이 예기치 않게 시작되는 것을 원하지 않습니다. 이러한 업데이트 단계 중 일부는 큰 테이블에서 몇 시간이 걸릴 수 있습니다. -데이터 작업 ...)


3
이 코드는 주문형 테이블을 생성하는 일종의 DatabaseLogger입니다. 이주도없고 재미있는 사업도 없습니다. 그러나 당신은 완전히 옳습니다. 코드를 적절히 리팩토링하겠습니다.
DR

4
또한 높은 특권 컨텍스트 (예 : 관리자)에서 실행하기 위해서는 배포 / 설정이 완벽하게 작동하지만 정상적인 운영은 그렇지 않습니다. 현재 당신은 CREATE TABLE정상적인 작전을위한 보조금 이 필요합니다 ...
Remus Rusanu
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.