반복 불가능 읽기와 팬텀 읽기의 차이점은 무엇입니까?


154

반복 불가능한 읽기와 팬텀 읽기의 차이점은 무엇입니까?

WikipediaIsolation (데이터베이스 시스템) 기사를 읽었 지만 몇 가지 의심이 있습니다. 아래 예제에서 반복 불가능한 읽기팬텀 읽기 ?

거래 A
SELECT ID, USERNAME, accountno, amount FROM USERS WHERE ID=1
산출:
1----MIKE------29019892---------5000
거래 B
UPDATE USERS SET amount=amount+5000 where ID=1 AND accountno=29019892;
COMMIT;
거래 A
SELECT ID, USERNAME, accountno, amount FROM USERS WHERE ID=1

또 다른 의심은 위의 예에서 어떤 격리 수준을 사용해야합니까? 그리고 왜?


답변:


165

Wikipedia에서 (이에 대한 훌륭하고 자세한 예가 있음) :

반복 불가능한 읽기는 트랜잭션이 진행되는 동안 행이 두 번 검색되고 행 내의 값이 읽기마다 다를 때 발생합니다.

팬텀 읽기는 트랜잭션 과정에서 두 개의 동일한 쿼리가 실행되고 두 번째 쿼리에서 반환 된 행 컬렉션이 첫 번째 쿼리와 다른 경우에 발생합니다.

간단한 예 :

  • 사용자 A는 동일한 쿼리를 두 번 실행합니다.
  • 그 사이에 사용자 B는 트랜잭션을 실행하고 커밋합니다.
  • 반복 불가능한 읽기 : 사용자 A가 조회 한 A 행은 두 번째로 다른 값을 갖습니다.
  • 팬텀 읽기 : 쿼리의 모든 행이 이전과 이후에 동일한 값을 갖지만 다른 행이 선택되고 있습니다 (B가 일부를 삭제하거나 삽입했기 때문에). 예 : select sum(x) from table;행이 추가되거나 삭제 된 경우 영향을받는 행 자체가 업데이트되지 않은 경우에도 다른 결과를 반환합니다.

위의 예에서 어떤 격리 수준을 사용해야합니까?

필요한 격리 수준은 응용 프로그램에 따라 다릅니다. "더 나은"격리 수준 (예 : 동시성 감소)에는 비용이 많이 듭니다.

예를 들어, 기본 키로 식별되는 단일 행에서만 선택하기 때문에 팬텀 읽기가 없습니다. 반복 불가능한 읽기를 수행 할 수 있으므로 문제가있는 경우이를 방지하는 격리 레벨을 원할 수 있습니다. Oracle에서 트랜잭션 A는 SELECT FOR UPDATE를 발행 할 수 있으며 트랜잭션 B는 A가 완료 될 때까지 행을 변경할 수 없습니다.


6
나는 그런 구문의 논리를 정말로 이해하지 못한다 .... 반복 할 수없는 읽기는 읽기가 반복 될 때 발생한다 (그리고 다른 값을 얻을 때) ??! ...
serhio

14
@serhio "반복 불가능"은 값을 한 번 읽고 x를 결과로 얻은 다음 다시 읽고 y를 결과로 얻을 수 있으므로 두 개의 동일한 결과를 반복 할 수 없다는 사실을 나타냅니다. 행 값이 읽기 사이에 업데이트되었으므로 동일한 행의 개별 쿼리.
BateTech

@Thilo 반복 가능한 읽기로 인해 문제가 발생하고 필요한 실제 사용 사례는 무엇입니까?
user104309

다른 거래에서 PK를 수정하면 어떻게됩니까? 그 결과 팬텀을 읽을 수 있습니까? (대부분의 경우 이상한 일이지만 불가능하지는 않습니다.)
jpmc26

1
둘 다 나에게 동일하게 들린다
sn.anurag

125

내가 생각하는 간단한 방법은 다음과 같습니다.

반복 불가능 및 팬텀 읽기는 트랜잭션이 시작된 후 커밋 된 다음 다른 트랜잭션의 데이터 수정 작업과 관련이 있습니다.

반복 불가능한 읽기는 트랜잭션 이 다른 트랜잭션에서 커밋 된 UPDATES 를 읽는 경우 입니다. 동일한 행은 이제 거래가 시작되었을 때와 다른 값을 갖습니다.

비슷하지만 최선을 다하고에서 읽을 때 팬텀 읽기 인서트 및 / 또는 DELETES 다른 트랜잭션에서. 트랜잭션을 시작한 후 사라진 새 행이 있습니다.

더티 읽기는 반복 불가능 및 팬텀 읽기와 유사 하지만 커밋되지 않은 데이터 읽기와 관련이 있으며 다른 트랜잭션에서 UPDATE, INSERT 또는 DELETE를 읽을 때 발생하며 다른 트랜잭션이 아직 데이터를 커밋하지 않은 경우에 발생합니다. "진행 중"데이터를 읽는 중입니다.이 데이터는 완전하지 않을 수 있으며 실제로 커밋되지 않을 수 있습니다.


4
트랜잭션 격리 수준 및 동시성과 관련이 있습니다. 기본 격리 수준을 사용하면 더티 읽기가 발생하지 않으며 대부분의 경우 더티 읽기를 피하려고합니다. 더티 읽기를 허용하는 격리 수준 또는 쿼리 힌트가 있습니다. 경우에 따라 더 높은 동시성을 달성하기 위해 허용 가능한 트레이드 오프이거나 다른 연결에서 진행중인 트랜잭션 문제를 해결하는 등의 경우에 필요합니다. 더티 (dirty) 읽기에 대한 아이디어가 일반적으로 bc "악취 테스트"를 통과하지 않는 것이 좋습니다. BC는 일반적으로 피해야하지만 목적이 있습니다.
BateTech

1
@PHPAvenger는 커밋되지 않은 읽기 격리 수준의 사용 사례입니다. 선택과 업데이트 쿼리 사이에 교착 상태가 발생할 가능성이 항상 있습니다 ( 여기 설명 ). 선택 쿼리가 커버링 인덱스를 생성하기에 너무 복잡한 경우 교착 상태를 피하기 위해 더티 읽기가 발생할 위험이있는 READ UNCOMMITED 격리 수준을 사용하려고하지만 더티 읽기에 대해 걱정하지 않기 위해 트랜잭션을 얼마나 자주 롤백합니까? 영구?!
petrica.martinescu

1
더티 읽기로 인해 발생하는 문제는 트랜잭션 롤백 여부에 관한 것이 아닙니다. 더티 읽기는 보류중인 트랜잭션의 데이터가 수정 된 방식에 따라 매우 부정확 한 결과를 반환 할 수 있습니다. 일련의 여러 삭제, 업데이트 및 / 또는 삽입을 수행하는 트랜잭션을 상상해보십시오. "미 확약 읽기"를 사용하여 해당 트랜잭션 도중에 데이터를 읽으면 불완전합니다. 커밋되지 않은 읽기에 대한 훨씬 좋은 대안은 SQL Server의 스냅 숏 격리 수준입니다. 프로덕션 시스템에서 커밋되지 않은 읽기 격리 수준의 올바른 사용 사례는 드문 IMO입니다.
BateTech

2
@ DiponRoy 좋은 질문입니다. 반복 가능한 읽기 (RR) 격리를 사용하는 경우 구현 된 잠금은 선택된 행에서 삭제가 발생하지 않도록해야합니다. 몇 년 동안 2 개의 iso 레벨에 대한 다양한 정의를 보았습니다. 주로 팬텀은 반환 된 collection / # 행의 변경이며 RR은 변경되는 동일한 행입니다. 방금 업데이트 된 MS SQL 설명서에서 삭제로 인해 비 RR ( docs.microsoft.com/en-us/sql/odbc/reference/develop-app/… )이 발생할 수 있다고 말 했으므로 삭제를 그룹화하는 것이 안전하다고 생각합니다. RR 카테고리
BateTech

2
@anir yes 삽입 및 삭제가 더티 읽기에 포함됩니다. 예 : 트랜잭션을 시작하고 연결 a에 100 개의 송장 라인 2 개를 삽입하십시오. 이제 연결 b는 trx가 커미트되기 전에 그리고 다른 98 개 라인이 추가되기 전에 2 개의 라인을 읽으므로 송장에 대한 모든 정보를 포함하지 않습니다. 이것은 삽입과 관련된 더티 읽기입니다.
BateTech

28

이 기사 에서 설명한 것처럼 , 반복 불가능한 읽기 예외는 다음과 같습니다.

여기에 이미지 설명을 입력하십시오

  1. Alice와 Bob은 두 개의 데이터베이스 트랜잭션을 시작합니다.
  2. Bob의 게시물 레코드를 읽고 제목 열 값은 Transactions입니다.
  3. Alice는 지정된 게시물 레코드의 제목을 ACID 값으로 수정합니다.
  4. Alice는 데이터베이스 트랜잭션을 커밋합니다.
  5. Bob이 사후 레코드를 다시 읽으면이 테이블 행의 다른 버전을 보게됩니다.

에서 이 문서 에 대한 팬텀 읽기 , 당신은 다음과 같이 이상이 발생할 수 있음을 볼 수있다 :

여기에 이미지 설명을 입력하십시오

  1. Alice와 Bob은 두 개의 데이터베이스 트랜잭션을 시작합니다.
  2. Bob은 식별자 값이 1 인 게시 행과 관련된 모든 post_comment 레코드를 읽습니다.
  3. Alice는 식별자 값이 1 인 게시물 행과 관련된 새로운 post_comment 레코드를 추가합니다.
  4. Alice는 데이터베이스 트랜잭션을 커밋합니다.
  5. Bob이 post_id 열 값이 1 인 post_comment 레코드를 다시 읽으면이 결과 세트의 다른 버전을 관찰하게됩니다.

따라서 반복 불가능 읽기 는 단일 행에 적용되지만 팬텀 읽기 는 주어진 쿼리 필터링 기준을 만족하는 레코드 범위에 관한 것입니다.


3
최고의 시각화 @Vlad
dextermini

23

현상 읽기

  • 더티 읽기 : 다른 트랜잭션에서 UNCOMMITED 데이터 읽기
  • 반복 불가능한 읽기 :UPDATE다른 트랜잭션의쿼리에서COMMITTED 데이터 읽기
  • 팬텀 읽기 :다른 트랜잭션에서INSERT또는DELETE쿼리에서COMMITTED 데이터를 읽습니다 .

참고 : 다른 트랜잭션의 DELETE 문은 특정 경우 반복 불가능한 읽기를 일으킬 가능성이 매우 낮습니다. 불행히도 DELETE 문은 현재 트랜잭션이 쿼리하는 것과 동일한 행을 제거합니다. 그러나 이것은 드문 경우이며 각 테이블에 수백만 개의 행이있는 데이터베이스에서는 발생하지 않을 가능성이 훨씬 높습니다. 트랜잭션 데이터를 포함하는 테이블은 일반적으로 모든 프로덕션 환경에서 높은 데이터 볼륨을 갖습니다.

또한 실제 INSERT 또는 DELETES가 아닌 대부분의 사용 사례에서 UPDATES가 더 빈번한 작업 일 수 있습니다 (이 경우 반복 불가능한 읽기의 위험 만 남아 있습니다.이 경우 팬텀 읽기 는 불가능합니다). 이것이 바로 UPDATES가 INSERT-DELETE와 다르게 취급되고 그 결과로 나타나는 변칙의 이름도 다른 이유입니다.

UPDATES 만 처리하는 대신 INSERT-DELETE 처리와 관련된 추가 처리 비용도 있습니다.


다양한 격리 수준의 이점

  • READ_UNCOMMITTED는 아무것도 막지 않습니다. 제로 격리 수준입니다
  • READ_COMMITTED는 단 하나만 예방합니다. 즉 Dirty 읽기
  • REPEATABLE_READ는 더티 읽기와 반복 불가능 읽기의 두 가지 예외를 방지합니다.
  • 직렬화 가능은 더티 판독, 반복 불가능 판독 및 팬텀 판독의 세 가지 이상을 모두 방지합니다.

그렇다면 왜 트랜잭션 SERIALIZABLE을 항상 설정하지 않습니까? 위의 질문에 대한 대답은 SERIALIZABLE 설정으로 인해 트랜잭션이 매우 느려져 다시 원하지 않습니다.

실제로 트랜잭션 시간 소비는 다음 비율입니다.

SERIALIZABLE > REPEATABLE_READ > READ_COMMITTED > READ_UNCOMMITTED

따라서 READ_UNCOMMITTED 설정이 가장 빠릅니다 .


요약

실제로 사용 시간을 분석하고 격리 수준을 결정 하여 트랜잭션 시간을 최적화하고 대부분의 이상을 방지해야합니다.

기본적으로 데이터베이스에는 REPEATABLE_READ 설정이 있습니다.


1
반복 불가능한 읽기에 대해 UPDATE 또는 DELETE가 모두 발생할 수 있습니까? 아니면 UPDATE입니까?
Dipon Roy

1
업데이트 또는 삭제 모두 반복
불가능한

실제로 동일한 데이터베이스에서 다른 트랜잭션에 의해 실행되는 임의의 DELETE 문은 평균적으로 현재 트랜잭션에 대해 반복 불가능한 읽기를 일으킬 가능성이 매우 낮다는 것을 요약 할 수 있습니다. 그러나 동일한 삭제 문은 현재 트랜잭션에 대한 팬텀 읽기를 100 % 확률로 발생합니다. 그런 식으로 보면, 단어로 단어를 가져 가면 내 글이 약간 잘못되었습니다. 그러나 저는 독자에게 더 명확하게하기 위해 의도적 으로이 방법을 썼습니다.
Subhadeep Ray

간단하고 이해하기 쉬운 설명을 보려면 +1하십시오. 그러나 나는 대부분의 데이터베이스 (오라클, MySQL은) 읽기의 기본 격리 수준은 최선을 다하고 REPEATABLE_READ의 아마 위해 Postgress 사용하는 기본 생각
akila

7

이 두 종류의 격리 수준간에 구현에 차이가 있습니다.
"반복 불가능한 읽기"의 경우 행 잠금이 필요합니다.
"팬텀 읽기"의 경우, 테이블 잠금조차도 범위 잠금이 필요합니다. 2 단계 잠금 프로토콜
을 사용하여이 두 가지 수준을 구현할 수 있습니다 .


반복 읽기 또는 직렬화를 구현하기 위해 행 잠금을 사용할 필요가 없습니다.
a_horse_with_no_name 20:53에

5

반복 불가능한 읽기가있는 시스템에서 트랜잭션 A의 두 번째 쿼리 결과는 트랜잭션 B의 업데이트를 반영합니다. 새로운 금액이 표시됩니다.

팬텀 읽기를 허용하는 시스템에서 트랜잭션 B가 ID = 1 인 새 행 을 삽입 하면 두 번째 쿼리가 실행될 때 트랜잭션 A가 새 행을 보게됩니다. 즉, 팬텀 읽기는 반복 불가능한 읽기의 특별한 경우입니다.


팬텀 읽기에 대한 설명이 정확하지 않다고 생각합니다. 커밋되지 않은 데이터가 표시되지 않더라도 팬텀 읽기를 얻을 수 있습니다. Wikipedia의 예를 참조하십시오 (위의 설명에 링크되어 있음).
Thilo

1

받아 들여진 대답은 무엇보다도 둘 사이의 소위 구별이 실제로 중요하지 않다는 것을 나타냅니다.

"행이 두 번 검색되고 행 내의 값이 읽기간에 서로 다른 경우"는 동일한 행이 아니며 (올바른 RDB에서 동일한 튜플이 아님) "정확한 경우 두 번째 쿼리에서 반환 된 행은 첫 번째 쿼리와 다릅니다. "

"어떤 격리 수준을 사용해야합니까?"라는 질문에 대해, 데이터가 누군가 어딘가에 매우 중요할수록 Serializable이 유일한 합리적인 옵션 일 것입니다.


0

비 반복 읽기와 팬텀 읽기에는 약간의 차이가 있다고 생각합니다.

반복 불가능한 것은 거래 A와 B가 견인된다는 것을 의미합니다. 만약 B가 A의 수정을 알아 차릴 수 있다면 더티 리드가 발생할 수 있으므로 B는 A 커밋 후에 A의 수정을 알립니다.

새로운 문제가 있습니다 : A 커밋 후 A의 수정을 B에게 알리십시오. 즉, A가 B가 보유하고있는 행의 값을 수정한다는 것을 의미합니다 .B는 때때로 행을 다시 읽으므로 B는 처음으로 새로운 값을 얻습니다. 문제를 해결하기 위해 반복 불가능하다고 부릅니다. B가 시작될 때 B가 무언가를 기억하게합니다 (아직 기억해야 할 것을 모르기 때문에).

새로운 해결책에 대해 생각해 봅시다. 새로운 문제가 있음을 알 수 있습니다. B가 무언가를 기억하게 만들었으므로 A에서 발생한 모든 일에 영향을받을 수는 없지만 B가 일부 데이터를 테이블과 B에 삽입하려는 경우 테이블을 점검하여 레코드가 없는지 확인하십시오. 그러나이 데이터는 A에 의해 삽입되었으므로 약간의 오류가 발생할 수 있습니다. 우리는 그것을 Phantom-read라고 부릅니다.


0

반복 불가능한 읽기는 격리 수준이며 팬텀 읽기 (다른 트랜잭션에 의해 커밋 된 값 읽기)는 개념 (읽기 유형 (예 : 더티 읽기 또는 스냅 샷 읽기))입니다. 반복 불가능한 읽기 격리 수준은 팬텀 읽기를 허용하지만 더티 읽기 또는 스냅 샷 읽기는 허용하지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.