private-books-study / real-my-sql-book-study

real my sql book study 저장소
0 stars 1 forks source link

Study 4 ~ Syudy 8 진행 스터디 리마인드 #6

Open InJun2 opened 2 months ago

InJun2 commented 2 months ago

진행내용

7월 4일 RealMySQL 8챕터까지 리마인드 스터디 진행


하고싶은 이야기 및 문제를 답변으로 작성해주세요

InJun2 commented 1 month ago

1. MyISAM 과 다른 InnoDB의 장점은?

  1. 레코드 기반 잠금
    • 기존 MySQL은 테이블 수준 잠금을 사용하지만 InnoDB는 레코드 기반 잠금을 통해 조회에서 불필요하게 테이블을 잠글 필요가 없어 속도가 빠름
    • 데이터 베이스의 동시성을 높이고 잠금 경합을 줄여 문제가 줄음
    • 또한 InnoDB는 잠금 에스컬레이션을 지원하지 않아 작은 잠금이 커다란 잠금으로 자동 변환되지 않고 행 수준 잠금을 유지함


  1. 트랜잭션 지원 메타 데이터
    • 기존 파일 기반 메타데이터를 생성하는 일은 서버가 비정상적으로 종료되면 일관되지 않은 상태로 남기도 했음
    • InnoDB는 테이블 구조 정보나 스토어드 프로그램 코드 등의 메타데이터를 InnoDB 별도의 테이블에 저장하여 통채로 mysql.ibd 테이블 스페이스에 저장함


  1. 프라이머리 키 클러스터링
    • InnoDB의 모든 테이블은 기본적으로 프라이머리 키를 기준으로 클러스터링 되어 저장하여 모든 세컨더리 인덱스는 레코드 주소 대신 프라이머리의 키의 값을 논리적 주소로 사용함
    • 프라이머리 키로 클러스터링 하면 연속되는 데이터를 조회하기 좋고 쿼리 실행 계획에서 프라이머리 키를 이용한 레인지 스캔은 상당히 빠르며 다른 키보다 비중이 높게 설정됨


  1. 외래 키 지원
    • 외래 키는 부모 테이블과 자식 테이블 간의 연관 관계 존재로 한 테이블에서 체크 작업이 일어나면 다른 테이블이 연달아 잠김이 전파되어 수동 데이터 적재나 스키마 변경 작업이 실패해 기존에는 외래 키를 사용하지 않는 경우가 빈번
    • InnoDB는 foreign_key_checks 시스템 변수 설정을 통해 일시적으로 외래 키에 대한 체크 작업을 멈출 수 있어 부가적인 체크가 없어 빠르게 처리할 수 있음
    • 그러나 일시적으로 해제하지만 이후 부모/자식 테이블의 관계가 깨진 상태로 유지하면 안됨


  1. MVCC (Multi Version Concurrency Control)
    • 일반적으로 레코드 레벨의 트랜잭션을 지원하는 DBMS가 제공하는 기능으로 MVCC의 가장 큰 목적은 잠금을 사용하지 않는 일관된 읽기를 제공함
    • InnoDB는 언두 로그(Undo log)를 이용하여 데이터가 변경될 때 버퍼 풀에서의 데이터는 변경되지만 디스크에는 아직 변경되지 않을 동안 해당 데이터를 조회할 가능성이 있음
    • 해당 경우 언두 로그는 아직 반영되지 않은 이전 데이터를 저장해두고 트랜잭션 격리 수준에 따라 커밋이 되기 전 혹은 이후 데이터를 제공할 수 있음


  1. 리두 로그
    • 데이터를 영구히 저장하기 전에 변경 사항을 기록하는 로그
    • 시스템 장애 시 데이터의 일관성을 보장하며 모든 데이터 변경을 순차적으로 기록하여 시스템 충돌이나 장애가 일어나면 리두 로그를 사용해 마지막 일관된 상태로 복구가 가능


  1. 자동 데드락 감지
    • InnoDB는 내부적으로 잠금이 교착 상태에 빠지지 않았는지 잠금 목록을 그래프 형태로 관리하여 데드락 감지 스레드가 주기적으로 잠금 대기 그래프를 검사해 교착 상태에 빠진 트랜잭션 중 하나를 강제 종료함
    • 어떤 트랜잭션을 먼저 강제 종료하는지 판단하는 기준은 트랜잭션의 언두 로그 양임
    • 동시 처리 스레드가 많다면 일반적인 서비스에서 데드락 감지 스레드가 잠금 목록을 검사하는데 많은 자원을 소모할 수도 있어 innodb_deadlock_detect 시스템 변수를 통해 데드락 감지 스레드를 작동하지 않게 할 수 있음


  1. 자동화 장애 복구
    • InnoDB는 손실이나 장애로부터 데이터를 보호하기 위한 여러 매커니즘이 탑재되어 있어 일부만 데이터가 기록되면 일련의 복구 작업이 자동으로 진행 됨
    • InnoDB는 매우 견고하여 데이터 파일 손상이나 MySQL 서버가 실행되지 못하는 경우는 매우 적지만 복구를 못하는 경우가 발생할 수도 있는데 해당 경우 복구는 쉽지 않으며 자동으로 복구될 수 없는 손상이 있다면 자동 복구를 멈추고 MySQL 서버는 종료됨


  1. 버퍼 풀
    • InnoDB 의 핵심적인 부분으로 디스크의 데이터 파일이나 인덱스 정보를 메모리에 캐시해두는 공간
    • 쓰기 작업을 지연하여 일괄 작업으로 처리할 수 있게하는 버퍼 역할도 같이함
    • 모아서 처리하여 랜덤 디스크 작업의 횟수를 줄일 수 있음
    • InnoDB 버퍼 풀은 크기를 동적으로 조절할 수 있어 처음에는 작게 점차 늘리며 적용하는 것을 추천
    • 50% 에서 버퍼풀을 지정해두고 설정을 찾는 것을 추천


2. MySQL 에서의 잠금 방법은 무엇이 있는지?

  1. 글로벌 락 (Global Lock)
    • 데이터베이스 서버 전체를 잠그기 위해 사용
    • 데이터베이스 백업 시 일관된 상태를 유지하기 위해 사용될 수 있음
    • 모든 데이터베이스와 모든 테이블을 읽기 전용 모드로 전환하여 서버 전체에 걸쳐 새로운 쓰기 작업이 불가능해짐


  1. 테이블 락 (Table Lock)
    • 특정 테이블에 대한 읽기 또는 쓰기 작업을 제어하기 위해 사용
    • 임의로 사용하면 안되며 MySQL 내부적으로 잠금을 동작
    • DDL은 사용하면 안되며 DML은 임의로 사용이 가능함
    • 데이터 이동이나 특정 테이블에 대한 원자적 작업 수행 시 사용
    • 특정 테이블에만 적용되어 읽기 잠금은 다른 세션이 해당 테이블을 읽을 수 있게 하지만, 쓰기 잠금은 모든 세션에서 해당 테이블에 대한 읽기 및 쓰기를 차단


  1. 레코드 락 (Record Lock)
    • 특정 행에 대한 쓰기 작업을 제어하기 위해 사용됩
    • 레코드를 잠그는 것이 아니라 인덱스를 잠그고 인덱스가 없다면 클러스트 인덱스를 만들어 잠금을 진행
    • 트랜잭션이 특정 행을 업데이트하거나 삭제할 때, 해당 행에 대한 다른 트랜잭션의 접근을 제어하기 위해 사용
    • 단일 행에 적용되어 다른 트랜잭션이 같은 행을 수정하지 못하게 함
    • 규모가 좁아 높은 동시성을 지원하며, 충돌 가능성을 줄이기 위해 세밀한 잠금을 제공함


  1. 네임드 락 (Named Lock)
    • 사용자가 정의한 임의의 리소스에 대한 잠금을 제공하기 위해 사용
    • 분산 환경에서 특정 리소스를 보호하거나 사용자 정의 동기화 메커니즘을 구현할 때 사용됨
    • 사용자 정의 잠금 이름에 대해 적용되어 같은 이름의 잠금에 대해서만 영향을 끼침
    • 다른 잠금 메커니즘과 독립적으로 작동하며, 특정 리소스나 작업을 보호하기 위해 유연하게 사용할 수 있음


  1. 메타 데이터 락 (Metadata Lock)
    • 테이블의 구조나 메타데이터를 변경할 때 데이터의 일관성을 보장하기 위해 사용
    • 테이블 구조 변경(예: ALTER TABLE), 인덱스 추가, 테이블 삭제 등의 작업 시 사용됨
    • 특정 테이블의 메타데이터에 대해 적용되어 메타데이터가 변경되는 동안 다른 세션이 해당 테이블에 접근하지 못하게 함
    • MySQL 내부적으로 관리되는 잠금으로, 테이블의 스키마 변경 작업을 보호함
    • 일반적으로 사용자가 직접 제어하지는 않음


기타 락

  1. 갭 락 (Gap Lock)

    • 인덱스 레코드 사이의 간격에 대한 잠금
    • InnoDB에서 다른 트랜잭션이 아직 존재하지 않는 레코드 간의 간격 (gap)을 잠그는 락으로 주로 범위 기반의 검색 쿼리에서 사용
    • 특정 범위를 잠근다고 가정했을 때 where id > 100 AND id < 200 에서 100과 200 사이의 레코드 간격을 잠금
    • 다른 트랜잭션이 해당 범위에 새로운 레코드를 삽입하지 못하도록 함
    • 팬텀 읽기를 방지하기 위한 잠금
  2. 넥스트 키 락 (Next-Key Lock)

    • 레코드와 인접한 간격을 잠그는 락
    • 갭 락을 보완하기 위해 사용되는 락으로, 범위 기반의 검색 쿼리에서 범위의 끝에 해당하는 키 다음에 오는 레코드를 잠그는 락으로 갭락보다 정밀한 잠금을 제공
    • 갭 락이 보호하지 못하는 트랜잭션의 범위 끝 다음의 키 값에 해당하는 레코드에 대한 접근을 제한하기 위해 사용
    • 인덱스에서 트랜잭션이 접근하려는 키 값 다음에 오는 레코드를 잠그는 것임
    • 트랜잭션 간의 격리 수준을 유지하면서 다른 트랜잭션이 레코드를 삽입하거나 수정하는 것을 방지
    • 팬텀 읽기를 방지하기 위한 잠금
  3. 인텐트 락 (Intent Lock)

    • 테이블 수준의 잠금 의도 표시. 상위 레벨 잠금 지원


3. 인덱스 사용 없이 특정 레코드를 변경/삭제 하면 일어나는 문제


스터디를 진행하고

kmw2378 commented 1 month ago

1. FK를 지양해야 하는 이유

2. MySQL에서 기본적으로 적용되는 트랜잭션 격리 수준과 장/단점

3. 인덱스를 활용하지 못하는 경우

4. 유니크 인덱스

5. 논 클러스터링 인덱스와 비교했을 때 클러스터링 인덱스의 장/단점

6. @Transactional(readOnly = true)를 써야되는 이유

스터디를 진행하고

실제 개발 시 당연시 여겼던 부분들을 공부할 수 있는 시간이였다. 특히, 자주 사용하는 트랜잭션과 인덱스에 대해 깊이 알게되었다.

인덱스가 무조건적으로 좋다고 알고 있었지만 인덱스를 통해 레코드를 가져오는 비용이 4 ~ 5배 정도 비싸다고 알게 되어 인덱스 사용시 주의를 해야 될 것 같다.

트랜잭션의 격리 수준도 고려를 해야될 것 같다. MySQL은 기본적으로 MVCC를 사용하는 Repeatable Read 방식을 사용하므로 Phantom Read 현상을 주의하고 트랜잭션 시간을 가능한 작게하여 언두 로그양이 많아져 성능 저하 발생을 최소화해야 될 것 같다.

JPA 엔티티간 일대다 연결을 사용하지 않고 Long 타입 PK를 연결하는게 좋다는 것도 알게되었다. 대부분 프로젝트에서 이렇게 했는데 왜인진 잘 몰랐는데 이번 기회에 자세히 알게되었다. 참고

또한, JpaRepository<T, ID> 에서 기본 제공하는 CRUD 메서드를 가급적이면 지양하는게 좋다는 것도 알게되었다. 나는 기본 메서드는 한계가 있어 대부분을 JPQL과 QueryDSL로 작성했는데 다른 이유가 있는줄은 몰랐다.