SELECT 쿼리에 대한 SQL Server 잠금 이해


79

SELECT WITH (NOLOCK)테이블에 영향을 미치는 유일한 다른 쿼리가 쿼리 인 경우 테이블 에서 사용하는 이점이 무엇인지 궁금 SELECT합니다.

SQL Server는 어떻게 처리합니까? 겠습니까 SELECT쿼리는 다른 블록 SELECT쿼리를?

저는 SQL Server 2012와 Linq-to-SQL을 사용하고 DataContext있습니다.

(편집하다)

성능 정보 :

  • 잠금을 사용하는 경우 두 번째 SELECT는 첫 번째 SELECT가 완료 될 때까지 기다려야 SELECT합니까?
  • SELECT WITH (NOLOCK)?

답변:


178

SELECTSQL Server의 A 는 테이블 행에 공유 잠금을 설정합니다. 두 번째 SELECT는 공유 잠금이 필요하며 서로 호환됩니다.

따라서 아무도 SELECT다른 사람을 차단할 수 없습니다 SELECT.

어떤 WITH (NOLOCK)쿼리 힌트가 사용되는 것은 (다른 연결에 의해)에 삽입되는 과정에있어 그이 아직 커밋되지 않은 데이터를 읽을 수있다.

해당 쿼리 힌트가 없으면 해당 작업의 트랜잭션이 커밋 (또는 롤백) 될 때까지 행 (또는 전체 테이블)에 배타적 잠금을 설정 SELECT하는 진행중인 INSERT(또는 UPDATE) 문에 의해 테이블 ​​읽기가 차단 될 수 있습니다 .

WITH (NOLOCK)힌트의 문제 는 : 당신이 전혀 삽입되지 않을 데이터 행을 결국 읽을 수 있다는 것입니다 ( INSERT트랜잭션이 롤백 된 경우 )-예를 들어 보고서에 실제로 데이터베이스에 커밋되지 않은 데이터가 표시 될 수 있습니다. .

유용 할 수있는 또 다른 쿼리 힌트가 있습니다 WITH (READPAST). 이것은 SELECT읽기를 시도하고 배타적으로 잠긴 행을 건너 뛰 도록 명령에 지시합니다 . 은 SELECT차단되지 않으며 "더러운"커밋되지 않은 데이터를 읽지 않지만 일부 행을 건너 뛸 수 있습니다 (예 : 테이블의 모든 행을 표시하지 않음).


1
좋은 대답, 감사합니다! 이유없이 SELECT사용하면 수백 개의 쿼리 에 영향이 WITH (NOLOCK)있습니까?
Francis P

3
우리는 농담없이 우리 선택의 99.5 %에서 nolock과 함께 사용합니다. 관리자가 사용자 레코드를 업데이트하는 경우 보고서가 거기에 있고 전체 분산 트랜잭션이 완료 될 때까지 기다리지 않도록합니다. 따라서 이전 데이터가 보고서에 표시됩니다. 무슨 상관이야? 보고서가 1 초 전에 실행 된 경우 rowlock에 있었던 것과 동일한 데이터입니다. 문제가되는 유일한 곳은 아직 커밋되지 않은 데이터입니다. 잠재적으로 문제가 될 수있는 "지난 1 시간 동안의 주문"을 표시하는 경우 속도 / 동시성 향상에 비해 아주 작은 문제입니다.
브라이언 화이트

5
또한 '신고'가 예로 제시 되었기 때문에 신고는 일반적으로 지난 5 분이 아닌 기간에 대한 것입니다. nolock으로 지난 달의 데이터보고-데이터가 한 달 후에 롤백되는 것과는 다릅니다.
Brian White

2
@FrancisP : 적은 수의 행을 삽입하는 경우가 아닙니다.이 경우 삽입되는 새 행을 잠급니다. 한 번에 약 5000 개 이상의 행을 삽입하면 잠금 에스컬레이션이 발생하고 전체 테이블이 독점적으로 잠 깁니다.
marc_s

1
아주 좋은 대답 .. SQL 잠금에 대한 하나의 튜토리얼처럼 느껴졌습니다 !! 여기 들어 와서 기뻐요!
digitally_inspired

32

성능에 대해서는 계속해서 선택에 집중합니다.
Shared는 읽기를 차단하지 않습니다.
공유 잠금 블록 업데이트.
수백 개의 공유 잠금이있는 경우 공유 잠금이 지워질 때까지 기다려야하므로 배타적 잠금을 얻기 위해 잠시 업데이트가 필요합니다.

기본적으로 선택 (읽기)은 공유 잠금을 사용합니다.
공유 (S) 잠금을 사용하면 동시 트랜잭션이 리소스를 읽을 (SELECT) 수 있습니다.
다른 선택에 영향을 미치지 않는 공유 잠금 (1 또는 1000).

차이점은 nolock 대 공유 잠금이 업데이트 또는 삽입 작업에 미치는 영향입니다.

리소스에 공유 (S) 잠금이있는 동안에는 다른 트랜잭션이 데이터를 수정할 수 없습니다.

공유 잠금이 업데이트를 차단합니다!
그러나 nolock은 업데이트를 차단하지 않습니다.

이는 업데이트 성능에 큰 영향을 미칠 수 있습니다. 또한 인서트에 영향을 미칩니다.

더티 읽기 (nolock)는 더럽게 들립니다. 부분적인 데이터를 얻을 수는 없습니다. 업데이트가 John을 Sally로 변경하면 Jolly를 얻을 수 없습니다.

동시성을 위해 공유 잠금을 많이 사용합니다. 데이터를 읽는 즉시 부실합니다. 다음 밀리 초 후에 Sally로 변경되는 John의 읽기는 오래된 데이터입니다. 다음 밀리 초 후에 John이 롤백되는 Sally 읽기는 오래된 데이터입니다. 그것은 밀리 초 수준입니다. 사용자가 공유 잠금을 사용하는 경우 실행하는 데 20 시간이 걸리고 사용자가 잠금을 사용하지 않는 경우 실행하는 데 4 시간이 걸리는 데이터 로더가 있습니다. 이 경우 공유 잠금으로 인해 데이터가 16 시간 유효하지 않게됩니다.

nolocks를 잘못 사용하지 마십시오. 그러나 그들은 장소가 있습니다. 바이트가 1로 설정되어있을 때 체크를 잘라 내고 체크가 끊어 질 때 2로 설정하려면-nolock 시간이 아닙니다.


2
감사합니다. 유사한 성능 특성을 볼 수 있습니다. 읽기를 위해 잠금이 필요한 경우 사이트가 실행되지 않으며 대부분의 경우 잠금이없는 경우의 영향은 미미합니다.
Brian White

@BrianWhite 감사합니다. 누군가 그것을 얻습니다. 그리고 업데이트 및 삽입시 많은 테이블 잠금을 사용합니다. 들어가고, 끝내고, 나가는 것이 나의 접근 방식입니다.
paparazzo

2
더티 읽기 (nolock)는 더럽게 들립니다. 부분적인 데이터를 얻을 수는 없습니다. 업데이트가 John을 Sally로 변경하면 Jolly를 얻을 수 없습니다. -존을 읽었 죠?
MonsterMMORPG

2
SQL Server의 업데이트는 나중에 배타적 잠금 (X)으로 변환되는 업데이트 잠금 (U)을 사용합니다. ( madeiradata.com/role-update-lock-sql-server 참조 ) 업데이트 잠금은 공유 잠금을 차단하지 않지만 배타적 잠금은 다른 모든 잠금을 차단합니다 ( msdn.microsoft.com/en-us/library/ms186396(v= sql.105) .aspx ).
kolobok

@kolobok 배타적 잠금 얻기 위해 업데이 트를 걸릴 것
파파라치

10

중요한 코멘트를 추가해야합니다. 모두가 NOLOCK더티 데이터 만 읽는 다고 언급하고 있습니다. 이것은 정확하지 않습니다. 또한 동일한 행을 두 번 얻거나 읽는 동안 전체 행을 건너 뛸 수도 있습니다. 이유는 SQL Server가 b- 트리의 균형을 재조정 할 때 동시에 일부 데이터를 요청할 수 있기 때문입니다.

다른 스레드 확인

https://stackoverflow.com/a/5469238/2108874

http://www.sqlmag.com/article/sql-server/quaere-verum-clustered-index-scans-part-iii.aspx )

NOLOCK 힌트 (또는 세션의 격리 수준을 READ UNCOMMITTED로 설정)를 사용하면 일관성을 기대하지 않는다고 SQL Server에 알릴 수 있으므로 보장 할 수 없습니다. "일관되지 않은 데이터"는 나중에 롤백 된 커밋되지 않은 변경 사항이나 트랜잭션의 중간 상태에서 데이터 변경 사항을 볼 수 있음을 의미 할뿐만 아니라 유의하십시오. 또한 모든 테이블 / 인덱스 데이터를 검색하는 간단한 쿼리에서 SQL Server가 검색 위치를 잃거나 동일한 행을 두 번 얻을 수 있음을 의미합니다.


9

제 작업에서 우리는 동시에 많은 PC에서 실행되는 매우 큰 시스템을 가지고 있습니다. 매우 큰 테이블에는 수십만 개의 행이 있고 때로는 수백만 개의 행이 있습니다.

매우 큰 테이블에 대해 SELECT를 수행 할 때 사용자가 지난 10 년 동안 수행 한 모든 트랜잭션을 알고 싶어하고 테이블의 기본 키가 효율적인 방식으로 빌드되지 않은 경우 쿼리에 몇 분이 걸릴 수 있습니다. 실행합니다.

그런 다음 우리의 응용 프로그램은 여러 사용자의 PC에서 동시에 실행되어 동일한 데이터베이스에 액세스 할 수 있습니다. 따라서 누군가 다른 SELECT가 읽고있는 테이블에 삽입하려고하면 (SQL이 읽으려고하는 페이지에서) LOCK이 발생하고 두 트랜잭션이 서로를 차단합니다.

우리는 SELECT 문에 "NO LOCK"을 추가해야했습니다. 왜냐하면 많은 사용자가 동시에 많이 사용하는 테이블에 대한 거대한 SELECT 였고 우리는 항상 LOCKS를 가지고 있었기 때문입니다.

내 모범이 충분히 명확한 지 모르겠습니까? 이것은 실제 사례입니다.


예를 들어 주셔서 감사합니다.하지만 다른 SELECT 쿼리에 영향을주는 SELECT 쿼리에 대해서만 궁금합니다 (동일한 테이블에서) ..
Francis P

1
그렇지는 않지만 select 문은 업데이트를 포함하는 트랜잭션의 일부가 될 수 있습니다. 업데이트 tbl set x = (select max (y) from tbl) where z = (select min (a) from tbl). tbl에서 동시 선택 z가 있으면 다른 선택이 차단하지 않지만 업데이트가 있습니다.
Brian White

1
나는 오랫동안 실행 선택 내 삽입을 차단하는 것을 정확하게이 문제를 가지고 있었다
nojetlag

2
거래는 서로를 차단하지 않으며 선택은 업데이트를 차단합니다. 다음은이 물건의 작동 방식에 대해 조금 더 이해하는 데 도움이되는 몇 가지 흥미로운 링크입니다. 첫 번째 1
JonnyRaa

@JonnyLeeds : 두 번째 링크가 더 이상 작동하지 않습니다. 다음은 SQL Server
stomy

3

SELECT WITH (NOLOCK)수는 필요에 해당 커밋되지 않은 데이터의 읽고 READ UNCOMMITTED데이터베이스에 격리 수준을 설정합니다. NOLOCK키워드는 전체 데이터베이스에서 격리 수준을 설정하는 것보다보다 정밀한 제어 할 수 있습니다.

Wikipedia에는 ​​유용한 기사가 있습니다. Wikipedia : Isolation (데이터베이스 시스템)

다른 stackoverflow 기사에서도 자세히 설명합니다.


제공 한 추가 정보에 대해 rghome에게 감사드립니다.
Francis P

이것이 유효한 사용 사례 일 힌트 READUNCOMMITTED(에 대한 별칭)를 사용하는 것을 선호하는 이유 입니다. 이렇게하면 실제로 "잠금 이없는 " 것이 아닌 실제 작업 덜 명확 해집니다. NOLOCK
user2864740 dec.

1

잠금없이 선택-삽입되거나 삽입되지 않을 레코드를 선택합니다. 더티 데이터를 읽을 것입니다.

예를 들어 트랜잭션이 1000 개의 행을 삽입 한 다음 실패한다고 가정 해 보겠습니다.

선택하면 1000 개의 행이 표시됩니다.


그러나 해당 테이블에 삽입 할 레코드가없는 경우 NO LOCK은 여전히 ​​관련이 있습니까?
Francis P

전혀 그렇지 않다. 읽기는 둘 이상의 세션에서 획득 할 수있는 공유 잠금을 사용하기 때문입니다. 더티 데이터를 가져올 방법이 없습니다.
Royi Namir 2012

확실하지 않은 것에 대해서는 대답하지 않는 편입니다. :-)
Royi Namir 2012
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.