-
Phantom RowsDatabase 2024. 8. 6. 00:24
17.7.4 Phantom Rows
Phantom 문제는 트랜잭션 내에서 동일한 쿼리가 다른 시간에 다른 행 집합을 생성할 때 발생합니다. 예를 들어, 두 번 실행된 SELECT가 처음에는 반환되지 않은 행을 두 번째 실행 시 반환하면 그 행은 "Phantom " 행입니다.
child 테이블의 id 열에 인덱스가 있고, id 값이 100보다 큰 모든 행을 읽고 잠그고자 하는 경우:
SELECT * FROM child WHERE id > 100 FOR UPDATE;
쿼리는 id가 100보다 큰 첫 번째 레코드에서 시작하여 인덱스를 스캔합니다. 테이블에 id 값이 90과 102인 행이 있는 경우, 인덱스 레코드 범위에 설정된 잠금이 간격(이 경우 90과 102 사이의 간격)에 삽입을 잠그지 않으면, 다른 세션이 id가 101인 새 행을 테이블에 삽입할 수 있습니다. 동일한 트랜잭션 내에서 동일한 SELECT를 실행하면 쿼리가 반환하는 결과 집합에서 id가 101인 새 행(Phantom row)을 볼 수 있습니다. 행 집합을 데이터 항목으로 간주하면 새로운 팬텀 행은 트랜잭션의 격리 원칙을 위반하게 됩니다. 트랜잭션은 읽은 데이터가 트랜잭션 동안 변경되지 않도록 실행되어야 합니다.
팬텀을 방지하기 위해 InnoDB는 인덱스-행 잠금과 간격 잠금을 결합한 넥스트 키 잠금 알고리즘을 사용합니다. InnoDB는 테이블 인덱스를 검색하거나 스캔할 때 만난 인덱스 레코드에 공유 또는 배타 잠금을 설정하여 행 수준 잠금을 수행합니다. 따라서 행 수준 잠금은 실제로 인덱스-레코드 잠금입니다. 또한, 인덱스 레코드에 대한 넥스트 키 잠금은 해당 인덱스 레코드 이전의 간격에도 영향을 미칩니다. 즉, 넥스트 키 잠금은 인덱스-레코드 잠금과 인덱스 레코드 이전의 간격에 대한 간격 잠금입니다. 한 세션이 인덱스의 레코드 R에 공유 또는 배타 잠금을 가지고 있으면 다른 세션은 인덱스 순서에서 R 바로 전에 새로운 인덱스 레코드를 삽입할 수 없습니다.
InnoDB가 인덱스를 스캔할 때 마지막 레코드 이후의 간격도 잠글 수 있습니다. 앞의 예에서는 id 값이 100보다 큰 테이블에 삽입을 방지하기 위해 InnoDB가 설정한 잠금에는 id 값이 102 이후의 간격에 대한 잠금이 포함됩니다.
다음 키 잠금을 사용하여 애플리케이션에서 고유성 검사를 구현할 수 있습니다. 데이터를 공유 모드로 읽고 중복된 행을 보지 못하면 안전하게 행을 삽입할 수 있으며, 읽기 동안 행의 후속 요소에 설정된 넥스트 키 잠금이 다른 사람이 행의 중복을 삽입하는 것을 방지합니다. 따라서 넥스트 키 잠금을 사용하면 테이블에서 존재하지 않는 것을 "잠글" 수 있습니다.
간격 잠금은 17.7.1 InnoDB Locking에서 논의된 것처럼 비활성화할 수 있습니다. 이는 간격 잠금이 비활성화되면 다른 세션이 간격에 새로운 행을 삽입할 수 있으므로 팬텀 문제가 발생할 수 있습니다.
'Database' 카테고리의 다른 글
MVCC (Multi-Version Concurrency Control)와 언두 로그(Undo Log), 리두 로그(Redo Log) (0) 2024.08.06 넥스트 키 락(Next-Key Lock) in Database Systems (0) 2024.08.06 MariaDB Lock(이론) (0) 2023.04.01 MariaDB Isolation (0) 2023.04.01 MariaDB Lock(실전) (0) 2023.04.01