Real MySQL 8.0 1주차

TAEYONG KIM·2023년 4월 17일
0

MySQL

목록 보기
1/6

전반적인 내용은 Real MySQL 8.0 (백은빈 이성욱 지음) 책의 내용을 기반으로 정리한 내용입니다.
모든 저작권은 해당 저자분들에게 있습니다.


Database의 핵심은 곧 읽기와 쓰기

개발자 입장에서 물리적 공간에 대한 메모리 할당과 해제까지 고려해야 할까?

물리적 장치 ARM, Track, Sector, Cylinder의 작업과 물리적인 I/O 오버헤드까지 고려하기에는 범주가 넓다

LOWEST LEVEL에 대한 작업들을 Disk Manager에게 맡기고
S/W를 High Level에 대해 고려하도록 만들어주자

  • Page 단위, Frame 단위로 부르는 곳이 다르겠지만 일정한 크기로 나눈 블록이라고 볼 수 있다. 즉, Buffer Manager에게 관리되는 메모리의 크기는 같다.

  1. Page Requests시, DBMS가 Buffer Manager가 하는 일, Disk Space manager가 하는 일부터 실제 물리 메모리 공간까지 접근하는 일들을 범위에 포함해서 관리된다면 유지비용이 상당할 것이다.

DBMS는 DBMS Layer
Buffer Manager가 하는 일
Disk Space Manager가 하는 일
들을 계층적으로 고민해보고 이해하자


UNDO는 왜 필요할까?

결국 이전에 우리가 공부한 Disk Space Management와 Buffer Management를 어느정도 이해했다면 내용을 이해하는데 어렵지 않을 것이다.
작업을 수행하면서 프레임 내 페이지들이 버퍼 관리자의 버퍼 교체 알고리즘에 따라서 디스크에 출력될 수 있다. 작업 도중인데, 버퍼 교체는 전적으로 버퍼의 상태에 따라서 결정되기 때문에 Consistency로 바라봤을 때 문제가 발생함. 즉, 아직 완료되지 않은 트랜잭션이 수정한 페이지들이 디스크에 출력될 수 있으므로 해당 트랜잭션이 어떤 이유든 정상적으로 종료될 수 없게 되면 트랜잭션이 변경한 페이지들은 원상 복구되어야 한다. 이러한 복구를 UNDO라고 부르는 것이다. 만약 버퍼 관리자가 트랜잭션 종료 전에는 어떤 경우에도 수정된 페이지들을 디스크에 쓰지 않는다면, UNDO 작업은 메모리 버퍼에 대해서만 이루어지면 되는 식이다. BUT : 매우 큰 크기의 메모리 버퍼가 필요하다는 문제점 때문에 채택 X

STEAL 정책

  • STEAL : 수정된 페이지를 언제든지 디스크에 쓸 수 있는 정책
  • ¬STEAL: 수정된 페이지들을 최소한 트랜잭션 종료시점까지는 버퍼에 유지하는 정책
    STEAL 정책은 결국 수정된 페이지가 어떠한 시점에도 디스크에 써질 수 있기 때문에 필연적으로 UNDO 로깅과 복구를 수반하는데 거의 모든 DBMS가 채택하는 버퍼 관리 정책이다.

REDO는 왜 필요할까?

이제는 UNDO 복구의 반대 개념인 REDO 복구에 대해 알아볼 것이다.
커밋한 트랜잭션의 수정은 어떤 경우에도 유지 되어야 한다. 이미 커밋한 트랜잭션의 수정을 재반영하는 복구 작업을 REDO 복구라고 하는데, REDO 복구 역시 UNDO 복구와 마찬가지로 버퍼 관리 정책에 영향을 받음
트랜잭션이 종료되는 시점에 해당 트랜잭션이 수정한 페이지들을 디스크에도 쓸 것인가 여부로 두가지 정책이 구분

  • FORCE: 수정했던 모든 페이지를 트랜잭션 커밋 시점에 디스크에 반영하는 정책
  • ¬FORCE: 수정했던 페이지를 트랜잭션 커밋 시점에 디스크에 반영하지 않는 정책
    여기서 중요한 점은 ¬FORCE 정책이 수정했던 페이지를 디스크에 반영하지 않는다는 점이지 커밋 시점에 어떠한 것도 쓰지 않는다는 것은 아니다. 어떤 일들을 했었다고 하는 로그는 기록함.
    정리해보면 DBMS는 STEAL과 ¬FORCE 정책을 채택하고 있음.
    따라서 UNDO 복구와 REDO 복구가 모두 필요하다 이러한 복구 작업을 위해 가장 널리 쓰이는 구조가 Log(로그)인 것이다.

Log

로그는 로그 레코드의 연속이며 데이터베이스의 모든갱신 작업을 기록함.
대부분 DBMS는 성능 상의 이유로 하나의 로그를 유지함.
수정 전 이미지와 수정 후 이미지를 모두 가지고 있으면서 연산이 발생할 때 적절한 조치를 취한다.


Transaction 이란?

데이터베이스의 상태를 변화시키기 위해 수행하는 작업 단위라고 알려져 있다. 트랜잭션은 작업의 완전성을 보장

ACID

  • 원자성(Atomicity) : 트랜잭션이 Database에 모두 반영되거나, 혹은 전혀 반영되지 않아야함.
    All or Nothing / DBMS의 회복 모듈은 시스템이 다운되는 경우, 부분적으로 데이터베이스를 갱신한 트랜잭션의 영향을 취소함으로써 트랜잭션의 원자성을 보장

  • 일관성(Consistency): 트랜잭션의 작업 처리 결과는 항상 일관성 있어야 한다.
    트랜잭션이 수행되는 도중에 데이터베이스가 일시적으로 일관된 상태를 갖지 않을 수 있음 하지만 결과는 일관성을 가짐 ex) 전체 계좌 잔액 합계는 10,000 원

  • 고립성(Isolation): 둘 이상의 트랜잭션이 동시에 병행 실행되고 있을 때, 어떤 트랜잭션도 다른 트랜잭션 연산에 끼어들 수 없다.
    예를 들어, 현재 계좌 상태 : My 계좌 10,000, 부모님 계좌 : 0원 / 내 계좌의 10,000 금액에서 부모님 계좌로 5천원을 송금하는 트랜잭션이 수행하는 도중에 부모님 계좌로 10,000원이 입금되는 트랜잭션이 수행됐다면, 총 6000원의 금액이 존재해야 할 부모님 계좌에 여전히 0원으로 알고 있던 5천원 송금 트랜잭션때문에 5000원으로 입력된다. 따라서, 고립성이 보장되어야 함

  • 지속성(Durability): 트랜잭션이 성공적으로 완료되었으면, 결과는 영구적으로 반영되어야 한다.
    DBMS의 회복 모듈은 시스템이 다운되는 경우에도 트랜잭션의 지속성을 보장함.


Transaction Level

하나의 트랜잭션 내에서 또는 여러 트랜잭션 간의 작업 내용을 어떻게 공유하고 차단할 것인지를 결정하는 레벨을 의미함.

Transaction Level은 왜 존재할까?

트랜잭션이 안정하게 수행되기 위한 ACID는 이론적으로 완전히 보장되어야함

BUT, 성능과 동시성을 위해서 완화되는 경우들이 존재하기 때문에 Level이 존재함

단순히 암기가 아니라 Level이 왜 존재하는지 알아야 한다!

Lock과 Transaction
잠금과 트랜잭션은 비슷한 개념 같으나 Lock은 동시성을 제어하기 위한 기능이고, Transaction은
데이터의 정합성을 보장하기 위한 기능이다. 하나의 데이터를 여럴 커넥션에서 동시에 변경하려고 하는데
잠금이 없다면 하나의 데이터를 여러 커넥션에서 동시에 변경할 수 있게 된다. 결과적으로 해당 레코드
의 값은 예측할 수 없는 상태가 된다. 잠금은 여러 커넥션에서 동시에 동일한 자원을 요청할 경우
한 시점에는 하나의 커넥션만 변경할 수 있게 해주는 역할을 한다. 격리 수준이라는 것은 하나의 트랜잭션
내에서 또는 여러 트랜잭션 간의 작업 내용을 어떻게 공유하고 차단할 것인지를 결정하는 레벨을 의미함.

상태를 변화시킨다는 것 -> SQL 질의어를 통해 DB에 접근하는 것
많은 사람들이 트랜잭션에 대해 다룰 때, 은행의 입출금을 통한 예시를 둔다.
EX) 사용자 A가 사용자 B에게 만원을 송금한다. 1. 사용자 A의 계좌에서 만원을 차감한다. 출금 Update 문 2. 사용자 B의 계좌에서 만원을 추가한다. 입금 Update 문
이를 통틀어 하나의 트랜잭션이라고 하는데, 작업 단위는 출금 Update문 + 입금 Update문으로 볼 수 있다.
위 두 쿼리문 모두 성공적으로 완료되어야만 "하나의 작업(트랜잭션)"이 완료되는 것이다. Commit
작업 단위에 속하는 쿼리 중 하나라도 실패하면 모든 쿼리문을 취소하고 이전 상태로 돌아가야함. Rollback

  1. 갱신 손실(Lost Update): 수행 중인 트랜잭션이 갱신한 내용을 다른 트랜잭션이 덮어씀으로써 갱신이 무효가 되는 것
  2. 오손 데이터 읽기(Dirty Read): 완료되지 않은 트랜잭션의 갱신한 데이터를 읽는 것
  3. 반복할 수 없는 읽기(Unrepeatable Read): 한 트랜잭션이 동일한 데이터를 두 번 읽을 때 서로 다른 값을 읽는 것

    격리 수준은 어떤게 있을까?

  • READ UNCOMMITTED
    • 설명
      각 트랜잭션에서의 변경 내용이 Commit이나 Rollback 여부에 상관 없이 다른 트랜잭션에서 값을 읽을 수 있는데, 정합성에 문제가 많은 격리 수준이기 때문에 사용하지 않는 것을 권장
      Dirty READ
      따라서 트랜잭션 작업이 완료되지 않았는데도 다른 트랜잭션에서 볼 수 있게 되는 현상이다.
  • READ COMMITED
    • 설명
      RDB에서 대부분 기본적으로 사용되고 있는 격리 수준이다. Dirty READ와 같은 현상이 발생하지 않음 실제 테이블 값을 가져오는 것이 아니라 Undo 영역에 백업된 레코드에서 값을 가져옴.
      그렇다면 READ COMMITED는 문제가 없을까?
      트랜잭션 - 1이 Commit한 이후 아직 끝나지 않는 트랜잭션 - 2가 다시 테이블 값을 읽으면 값이 변경됨을 알 수 있다. 하나의 트랜잭션 내에서 SELECT 쿼리를 실행했을 때는 항상 같은 결과를 가져와야 하는 REPEATABLE READ의 정합성에 어긋난다
  • REPEATABLE READ
    • 설명
      MYSQL에서는 트랜잭션마다 트랜잭션 ID를 부여하여 해당 트랜잭션 ID보다 작은 트랜잭션 번호에서 변경한 것만 읽게 된다. UNDO 공간에 백업해두고 실제 레코드 값을 변경하는데, 백업된 데이터는 불필요하다고 판단하는 시점에 주기적으로 삭제함.
      UNDO에 백업된 레코드가 많아지면 MySQL 서버의 처리 성능이 떨어질 수 있음
  • SERIALIAZABLE
    • 설명
      가장 단순한 격리 수준이지만 가장 엄격한 격리 수준
      성능 측면에서는 동시처리 성능이 가장 낮다.
      SERIALIZABLE 에서는 Phantom Read가 발생하지 않는데 데이터베이스에서 거의 사용되지 않음 Phantom Read는 다른 트랜잭션에서 수행한 변경 작업에 의해 레코드가 보였다 안보이는 현상인데 이를 방지하기 위해서는 쓰기 잠금을 걸어야함.
profile
백엔드 개발자의 성장기

0개의 댓글