비용과 락에 대한 관점
1. Insert에서의 비용
1.
작업의 본질: insert는 새로운 데이터를 데이터베이스에 추가하는 작업이며, 일반적으로 해당 데이터의 위치를 찾고 데이터를 쓰는 것으로 마무리됩니다. 반면, update는 기존 데이터를 찾아서 읽고, 수정한 후에 다시 쓰는 과정을 포함합니다. 이 과정은 insert보다 더 많은 단계를 필요로 합니다.
2.
데이터 검색: update 작업은 기존 데이터를 검색해야 하므로, 해당 데이터를 찾는 데 시간이 걸릴 수 있습니다. 이는 특히 인덱스가 없거나 데이터베이스가 매우 큰 경우 더욱 두드러질 수 있습니다. insert는 이러한 검색 단계가 필요 없습니다.
3.
데이터 무결성 및 제약 조건: update 작업은 기존 데이터를 변경하기 때문에 데이터 무결성을 유지하기 위한 추가적인 제약 조건 검사가 필요할 수 있습니다. 예를 들어, 외래 키 제약 조건이나 트리거 등이 update 작업을 느리게 만들 수 있습니다. insert 작업도 이러한 제약 조건 검사가 필요하지만, 기존 데이터와의 상호 작용이 덜하기 때문에 일반적으로 덜 복잡합니다.
2. UPDATE 쿼리에서의 락
데이터 베이스의 격리 수준에 대해서 먼저 조회해봅니다.
`SELECT @@tx_isolation;`
—> `REPEATABLE-READ`
Python
복사
MariaDB에서 REPEATABLE READ 격리 수준(isolation level)을 사용할 때, UPDATE 쿼리와 SELECT 쿼리에서 다음과 같은 락이 수행됩니다
•
UPDATE 쿼리는 행에 대해 읽기 잠금(Read Lock)과 쓰기 잠금(Write Lock)을 모두 획득합니다.
•
해당 행에 대한 다른 트랜잭션의 읽기나 쓰기 작업을 차단하여, 일관성 있는 데이터 상태를 유지합니다.
•
UPDATE는 해당 행을 수정하므로, 다른 트랜잭션이 해당 행을 읽거나 변경할 수 없도록 합니다.
•
분할 업데이트: 큰 테이블의 경우, 한 번에 많은 행을 업데이트하는 대신 작은 배치로 나누어 업데이트를 수행할 수 있습니다.
◦
업데이트 트랜잭션이 오래 걸릴 경우, 해당 트랜잭션에 의해 락이 걸린 행이나 테이블을 조회하는 다른 사용자의 쿼리는 대기 상태가 될 수 있습니다
◦
하지만 벌크 업데이트를 수행하면서, 트랜잭션 범위를 얼마나 잡느냐에 따라 해당 테이블에 락이 걸려 동시성 오류가 발생합니다.
◦
따라서 트랜잭션을 행하는 행의 범위는 비지니스 룰에 따라 적정선을 타협하는 것이 중요합니다
•
또한 격리수준을 완화하는 것도 가능하지만 이는 권장되는 방법이 아닙니다.
•
자주 업데이트되는 칼럼에 인덱스를 거는 것도 하나의 방법이 될 수 있지만, 이는 인덱스와 쓰기 작업 성능, 디스크 공간과 같은 트레이드 오프를 고려해야합니다.
2. SELECT 쿼리에서의 락
•
REPEATABLE READ에서의 일반적인 SELECT 쿼리는 비공유 읽기 잠금(Non-Exclusive Read Lock)을 사용하지 않습니다.
•
즉, SELECT 쿼리만 수행하는 경우에는 다른 트랜잭션이 동일한 행을 읽을 수 있습니다.
•
그러나 SELECT ... FOR UPDATE 또는 SELECT ... LOCK IN SHARE MODE 구문을 사용하면, 각각 쓰기 잠금과 공유 읽기 잠금을 획득합니다.
REPEATABLE READ 격리 수준의 특징
•
REPEATABLE READ에서는 한 트랜잭션 내에서 수행되는 모든 읽기 작업이 트랜잭션이 시작될 때의 일관된 상태를 반영합니다.
•
다른 트랜잭션이 변경한 내용이 커밋되더라도 현재 진행 중인 트랜잭션에서는 변경 전의 데이터를 볼 수 있습니다.
◦
해당 작업을 언두 로그를 통해 읽게 됩니다.
•
이는 팬텀 읽기(Phantom Read)를 방지하지만, 간격 잠금(Gap Lock)을 사용하여 특정 레코드 범위에 대한 삽입을 차단할 수 있습니다.
주의사항
•
격리 수준에 따라 성능과 일관성 간의 트레이드오프가 존재합니다.
•
데이터베이스의 성능과 일관성 요구사항에 따라 적절한 격리 수준을 선택해야 합니다.
•
격리 수준의 설정은 데이터베이스 전역 설정 또는 세션별 설정으로 조절할 수 있습니다.