Post

CS-데이터베이스

데이터베이스에 대한 넓은 범위의 내용을 작성합니다.

데이터베이스

데이터베이스가 무엇인가?

데이터베이스란 전자적으로 저장되고 사용되는 관련있는 데이터들의 조직화된 집합이다. 관련있는 데이터란 같은 목적이나 서비스 안에서 생성되는 데이터를 말한다.

왜 데이터베이스를 사용하는가?

데이터베이스 이전에는 파일 시스템을 사용해서 데이터를 관리하였습니다. 이때 종속성이나 데이터무결성 등의 문제가 발생하였기 때문에 이 문제를 해결한 데이터베이스를 사용하게 되었습니다.

  • 데이터베이스를 사용해서 데이터의 무결성을 지킬 수 있고
  • 파일 시스템에는 없는 트랜잭션을 사용해서 작업의 완전성을 보장할 수 있기 때문이다.
DBMS가 무엇인가요?

DBMS는 사용자에게 DB를 정의하고 만들고 관리하는 기능을 제공하는 소프트웨어 시스템입니다.

스키마가 무엇인가?

데이터 모델을 바탕으로 데이터베이스의 구조를 기술한 것이다.

Key에 대한 설명
  • 후보키
    • 어느 하나의 속성이라도 제거하면 유일하게 튜플을 식별할 수 없는 슈퍼키
  • 기본키
    • 기본키는 후보키 중에서 선택한 메인 키입니다.
    • null 값을 가질 수 없고 중복될 수 없다는 특징을 가집니다.
  • 슈퍼키
    • 테이블에서 튜플을 유일하게 식별할수 있는 속성의 집합
  • 대체키
    • 후보키 중에서 기본키를 제외한 나머지를 말합니다.
  • 외래키
    • 다른 테이블의 PK를 참조하는 속성의 집합
기본키는 수정이 가능한가요?

연관관계가 없다면 변경이 가능합니다.

외래키의 값에는 null이 들어올 수 있나요?

기본키의 경우에는 고유성을 지니고 있어야 하기 때문에 null값이 들어오는 것이 허용되지 않지만 외래키는 null값이 허용됩니다.

제약조건(Constraints)가 무엇인가요?

관계형 데이터베이스의 테이블이 항상 지켜주어야하는 제약사항을 말합니다. 데이터의 일관성을 보장하기 위해서 사용합니다.

암묵적 Constrains란?

관계형 데이터 모델 자체가 가지는 제약조건을 말합니다.

  • 테이블을 중복된 튜플을 가질 수 없다.
  • 테이블 내에서 같은 이름의 속성을 가질 수 없다.

InnoDB 스토리지 엔진 아키텍쳐

InnoDB 엔진의 특징에 대해서 설명해주세요
  • PK에 의한 클러스터링
    • InnoDB 엔진은 MySQL에서 사용할 수 있는 스토리지 엔진 중에서 거의 유일하게 레코드 기반의 락을 제공하기 때문에 높은 수준의 동시성 처리가 가능합니다.
    • InnoDB의 모든 테이블은 기본적으로 PK를 기준으로 클러스터링 되어 PK순서대로 저장되기 때문에 PK를 이용한 레인지 스캔이 빠르게 처리됩니다.
  • MVCC(Multi Version Concurrentcy Control)
    • InnoDB는 언두로그를 사용해서 잠금을 사용하지 않는 일관된 읽기를 제공합니다.
    • 하나의 레코드에 대해서 여러개의 버전이 관리됩니다.
UPDATE 쿼리가 발생하면 InnoDB에서는 어떤 일이 발생하나요?

InnoDB 버퍼 풀이 새로운 데이터로 변경되고, 기존의 데이터는 언두영역으로 복사됩니다.

아직 COMMIT, ROLLBACK되지 않은 상태에서 다른 사용자가 작업중인 레코드를 조회하면 어떻게 되나요?

MySQL 시스템 변수로 설정된 격리 수준에 따라서 다른 결과가 발생합니다.

  • 격리수준이 READ UNCOMMITTED인 경우에는 InnoDB 버퍼 풀이 현재 가지고 있는 변경된 데이터를 읽어서 반환합니다. 즉, 커밋 여부와는 상관없이 변경된 데이터를 반환합니다.
  • 격리수준이 READ COMMITTED이거나 그 이상인 경우에는 아직 커밋되지 않았기 때문에 InnoDB 버퍼 풀이나 데이터 파일에 있는 내용 대신 변경되기 이전의 데이터를 가지고 있는 언두 영역의 데이터를 반환합니다.
InnoDB에서 COMMIT이 되면 어떤 일이 발생하나요?

더 이상의 변경작업 없이 현재 InnoDB 버퍼풀의 상태를 영구적인 데이터로 만들어 버립니다.

InnoDB에서 ROLLBACK이 되면 어떤 일이 발생하나요?

언두영역에 있는 백업된 데이터를 다시 InnoDB 버퍼 풀로 복구하고 언두영역의 데이터를 삭제합니다.

COMMIT되면 언두영역의 데이터가 삭제되는건가요?

언두영역을 필요로하는 트랜잭션이 더는 없을 때 삭제됩니다.

잠금없는 일관된 읽기가 뭔가요?

MVCC 기술을 사용해서 읽기작업을 수행하는 것을 말합니다. InnoDB에서는 변경 트랜잭션이 수행되고 있어도 다른 사용자의 조회 작업을 방해하지 않습니다.

InnoDB 버퍼 풀이 무엇인가요?

스토리지 엔진에서 가장 핵심적인 부분으로, 디스크의 데이터 파일이나 인덱스 정보를 메모리에 캐시해두는 공간입니다. 쓰기작업을 지연시켜 일괄작업을 할 수 있도록 해주는 버퍼 역할도 같이합니다.

트랜잭션

트랜잭션이 무엇인가요?

트랜잭션은 데이터베이스에 접근하는 작업의 논리적인 단위입니다. 논리적인 작업셋을 모두 완벽하게 처리하거나 처리하지 못할 경우에는 원 상태로 복구해서 작업의 일부만 처리되는 현상을 방지합니다.

ACID 원칙에 대해서 설명해주세요

ACID는 데이터베이스 트랜잭션을 안전하게 수행하기 위한 원칙을 의미합니다.

  • Atomicity(원자성): 트랜잭션이 원자적으로 수행되는 것을 보장하는 성질입니다. 즉, 트랜잭션 내의 모든 작업이 성공적으로 수행되거나 전혀 수행되지 않아야합니다.
  • Consistency(일관성): 트랜잭션이 수행된 이후에도 데이터베이스의 상태가 일관성을 유지해야한다는 것을 의미합니다. 일관성을 유지한다는 것은 데이터베이스의 제약조건을 만족하는 것을 의미합니다.
  • Isolation(독립성): 여러개의 트랜잭션이 동시에 수행되더라도 각각의 트랜잭션은 서로에게 영향을 주지 않아야한다는 것을 의미합니다. 즉, 트랜잭션은 다른 트랜잭션과 격리되어야함을 의미합니다.
  • Durability(영속성): 트랜잭션이 성공적으로 수행되면 그 결과가 데이터베이스에 영구적으로 유지되어야한다는 것을 의미합니다.
DBMS가 Consistency를 어떻게 보장해주나요?

DBMS는 Consistency를 보장하기 위해서 제약조건을 설정하고, 이를 위반하는 트랜잭션이 발생하는 것을 방지합니다.

  • 중복된 데이터를 입력하거나 FK 제약조건을 위반하는 데이터를 입력하는 것을 방지한다.
  • 트랜잭션 실행 중에 다른 사용자가 데이터를 수정하거나 삭제하는 것을 방지하기 위해 Locking 기능을 제공한다.
DBMS가 Durability를 어떻게 보장해주나요?
  • WAL(Write Ahead Logging)
    • 트랜잭션의 모든 변경사항을 로그에 기록합니다.
    • 트랜잭션이 완료되면 로그를 데이터베이스에 적용합니다.
    • 시스템 장애 발생시 로그를 사용하여 데이터베이스를 복구합니다.
  • 체크포인트
    • 체크포인트를 두어서 정기적으로 데이터베이스의 일관된 상태를 저장합니다.
    • 시스템 장애 발생시 체크포인트를 사용하여 데이터베이스를 빠르게 복구합니다.
체크포인트 방식을 사용하면 체크포인트 이후의 데이터는 손실될 수 있습니다. 이를 어떻게 해결하나요?
  1. 체크포인트 간격을 줄이는 방법을 사용할 수 있습니다. 하지만 체크포인트 간격을 줄이면 시스템 성능이 저하될 수 있기 때문에 데이터 손실 가능성과 시스템 성능간의 균형을 고려해서 적절한 체크포인트 간격을 설정해야합니다.
  2. 특정 조건 충족 시 강제로 체크포인트를 설정하여 데이터 손실 가능성을 줄일 수 있습니다.
  3. 데이터를 여러개의 저장 장치에 복제하여 손실가능성을 줄일 수 있다.
데이터 손실 가능성을 완전히 제거하려면 어떻게 해야하나요?

고가용성 클러스터(HA, High-Availablity cluster)를 사용해야합니다.

고가용성 클러스터가 무엇인가요?

고가용성 클러스터는 여러 서버를 하나의 시스템처럼 작동하도록 연결하여 시스템 중단시간을 최소화하는 컴퓨터 그룹입니다.

고가용성 클러스터를 사용해서 어떻게 장애에 대응하는가?
  • 장애 감지: 서버 또는 구성요소에 장애가 발생하면 클러스터 소프트웨어가 감지한다.
  • 장애 조치: 장애 발생 시 다른 서버가 자동으로 작업을 인계하여 서비스 중단없이 운영을 지속한다.
  • 자동 복구: 장애가 해결된 후에는 원래 서버가 다시 클러스터에 참여할 수 있도록 자동 복구가 진행된다.
리두로그는 언제 비워지나요?
  • 트랜잭션이 완료되었을 때
  • 체크포인트가 설정되었을 때 리두로그가 비워지고 새로운 리두로그가 생성됩니다.
  • 시스템이 종료되었을 때
  • 리두로그 공간이 부족하면 오래된 정보부터 삭제됩니다.
여러 트랜잭션이 한꺼번에 실행될 때 발생할 수 있는 이상현상에는 무엇이 있는가?
  • Dirty Read
    • 커밋되지 않은 변화를 읽었을 때 발생하는 현상입니다.
    • 다른 트랜잭션에 의해 롤백된 값을 이용한 경우 문제가 발생합니다.
  • Non-Repeatable Read(=Fuzzy Read)
    • 같은 데이터를 두번 읽었을 때 값이 달라지는 현상입니다.
    • 트랜잭션은 독립적인 환경인 것처럼 수행되어야 하는데 같은 데이터를 읽었을 때 다른 트랜잭션에게서 영향을 받을 것처럼 동작하기 때문에 이상현상으로 여겨집니다.
  • Phantom Read
    • 같은 조건으로 데이터를 읽었을 때 없었던 데이터가 생기는 현상
트랜잭션 격리 레벨에 대해서 설명해주세요

여러 트랜잭션이 처리될 때 트랜잭션끼리 얼마나 고립되어있는지를 나타냅니다. 트랜잭션에서 발생할 수 있는 이상현상을 정의하고 어떤 현상을 허용하는지에 따라서 각각의 격리 레벨에 정해집니다. 개발자는 격리레벨을 통해 전체 처리량과 데이터의 일관성 사이에서 트레이드오프를 따지게 됩니다. 격리 수준은 크게 READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, SERIALIZABLE 네가지 단계로 나뉩니다.

  • READ UNCOMMITTED
    • read uncommitted에서는 어떤 트랜잭션 변경 내용의 commit, rollback과는 상관없이 다른 트랜잭션에 보여집니다. dirty read와 같이 데이터 정합성에 문제가 있어서 RDBMS 표준에서는 격리수준으로 인정하지 않습니다.
  • READ COMMITTED
    • READ COMMITTED는 어떤 트랜잭션의 변경 내용이 commit되어야만 다른 트랜잭션에 조회할 수 있는 격리수준입니다.
    • 데이터가 중간에 바뀌고 커밋된 다음에 트랜잭션 내에서 똑같은 조회쿼리를 수행했을 경우 항상 같은 결과를 반환해야한다는 repeatable read 정합성에 어긋나게 됩니다.
  • REPEATABLE READ
    • 트랜잭션이 시작되기 전에 commit된 내용에 대해서만 조회할 수 있는 격리수준입니다.
    • 자신의 트랜잭션 번호보다 낮은 트랜잭션 번호에서 변경된 것만 보게 됩니다.
    • 트랜잭션이 시작된 시점의 데이터를 일관되게 보여주어야하기 때문에 트랜잭션의 실행시간이 길어질수록 해당시간만큼 멀티 버전을 관리해야하는 단점이 있습니다.
  • SERIALIZABLE
    • 가장 단순하고 엄격한 격리수준입니다.
    • 격리수준이 SERIALIZABLE일 경우 읽기작업이 공유잠금을 설정하게 된다.
    • 한 트랜잭션에서 읽고 쓰는 레코드를 다른 트랜잭션에서는 접근할 수 없게 된다.
    • 이러한 특성 때문에 동시처리능력이 다른 격리수준보다 떨어지고 성능저하가 발생하게 된다.
언두로그가 무엇인가요?

트랜잭션의 격리수준을 보장하기 위해서 DML(insert, update, delete) 쿼리로 변경되기 이전 버전의 데이터를 백업해두어야 합니다. 이 백업된 데이터를 언두로그라고 합니다.

언두로그를 왜 사용하나요?

트랜잭션의 롤백을 대비하기 위해서, 그리고 트랜잭션의 격리수준을 유지하면서 높은 동시성을 제공하기 위해서 그렇습니다.

언두로그가 어떻게 트랜잭션의 격리수준을 보장해주나요?

트랜잭션이 롤백되면 트랜잭션이 수행되기 이전의 데이터로 복구해야하는데, 이때 언두로그에 백업해둔 이전 버전의 데이터를 사용해서 복구합니다.
또 특정 커넥션에서 데이터를 읽고 변경하는 도중에 다른 커넥션에서 데이터를 조회하면 격리수준에 맞게 변경된 데이터가 아닌 언두로그에 백업해둔 데이터를 읽어서 반환하기도 합니다.

잠금과 트랜잭션의 차이점은?

잠금은 데이터의 동시성을 제어하기 위한 기능이고, 트랜잭션은 데이터의 정합성을 보장하기 위한 기능입니다.

트랜잭션을 사용하면서 주의해야할 점은?

프로그램의 코드가 데이터베이스 커넥션을 가지고 있는 범위와 트랜잭션이 활성화 되어있는 프로그램의 범위를 최소화 해야합니다. 그리고 다른 네트워크 작업이 트랜잭션의 중간에 위치하지 않도록 배제해야합니다. 네트워크통신에서 문제가 생기면 트랜잭션에러로 퍼져버립니다.

Concurrency Control

Concurrency Control이란?

어떠한 스케줄이라도 Serializable하게 만드는 역할을 수행하는 것이 Concurrency Control입니다.

스케줄이 무엇인가요?

스케줄이란 여러 트랜잭션이 동시에 실행될 때 각 트랜잭션에 속한 연산들의 실행순서를 말합니다.

Serial 스케줄이란?

트랜잭션이 겹치지 않고 한번에 하나씩 실행되는 스케줄을 말합니다.

  • 한번에 하나의 트랜잭션을 수행하기 때문에 이상한 결과를 만들어 낼 가능성은 없습니다.
  • 한번에 하나의 트랜잭션만 수행하기 때문에 좋은성능은 낼 수 없습니다.
Nonserial 스케줄이란?

트랜잭션들이 겹쳐서 실행되는 스케줄

  • 트랜잭션들이 겹쳐서 실행되기 때문에 동시성이 높아져서 같은 시간동안 더 많은 트랜잭션들을 처리할 수 있다.
  • 하지만 트랜잭션들이 어떤 형태로 겹쳐서 실행되느냐에 따라 이상한 결과가 나올 수 있습니다.
충돌(Conflict)의 조건에 대해서 설명해주세요
  1. 서로 다른 트랜잭션에 소속되고
  2. 같은 데이터에 접근하고
  3. 최소 하나이상의 트랜잭션은 쓰기(write)작업을 할 때

위 세가지 조건을 만족하면 두 연산은 충돌한다고 합니다.

Conflict Equivalent가 무엇인가요?

두개의 스케줄이 다음 두 조건을 만족하면 Confict EquiValent하다고 합니다.

  1. 두 스케줄이 같은 트랜잭션들을 가진다.
  2. 모든 충돌연산의 순서가 동일할 때
Conflict Serializable이 무엇인가요?

시리얼 스케줄과 Conflict Equivalent할 때 Conflict Serializable이라고 합니다. Conflict Serializable한 스케줄은 정상적인 결과를 만들어낸다는 특징이 있습니다.

Unrecoverable 스케줄이란?

스케줄 내에서 롤백된 트랜잭션이 쓰기작업을 한 데이터를 읽은 스케줄을 Unrecoverable schedule이라고 합니다. 이런 스케줄은 롤백해도 이전상태로 회복 불가능할 수 있기 때문에 DBMS가 허용하면 안됩니다.

Recoverable Schedule이란?

스케줄 내에서 어떤 트랜잭션도 자신이 읽은 데이터를 쓴 트랜잭션이 커밋이나 롤백하기 전까지 커밋하지 않는 스케줄을 말합니다. 이 방법을 사용하면 롤백할 때 이전상태로 온전히 돌아갈 수 있습니다.

Cascading Rollback이란?
  • 하나의 트랜잭션이 롤백되면 의존관계가 있는 트랜잭션도 롤백되는 스케줄
  • 여러 트랜잭션의 롤백이 연쇄적으로 일어나면 처리하는 비용이 많이 듭니다.
Cascadeless Schedule 이란?

스케줄 내에서 어떤 트랜잭션도 커밋되지 않은 트랜잭션이 쓴 데이터를 읽지 않는 경우를 말합니다.

Strict Schedule 이란?
  • 스케줄 내에서 어떤 트랜잭션도 커밋되지 않은 트랜잭션이 쓴 데이터는 읽지도 않고 쓰지도 않는 경우를 말합니다.
  • 롤백할때 트랜잭션을 이전 상태로만 되돌려 놓으면 되기 때문에 Recovery가 쉽다는 장점이 있다.
2PL(two-phase locking) 이란?
  • 트랜잭션의 모든 locking operation이 최초의 unlock operation보다 먼저 수행되도록 하는 것
  • 락을 획득만 하는 phase와 반환만 하는 phase로 나뉘어서 locking을 하기 때문에 two-phase locking 이라고 부릅니다.
2PL을 왜 사용하는가?
  • 스케줄의 Serializability를 보장하기 위해서.
2PL 프로토콜의 종류에 대해서 설명해주세요
  • conservative 2PL
    • 트랜잭션을 수행하는데 필요한 모든 lock을 획득한 다음에 시작하는 방식입니다.
    • 필요한 lock을 모두 획득하기 때문에 데드락이 발생하지 않는다는 장점이 있습니다.
    • 하지만 그만큼 트랜잭션을 시작하기 어려워져서 실용적인 방법은 아닙니다.
  • strict 2PL(S2PL)
    • strict schedule을 보장하는 2PL입니다.
    • strict schedule을 보장하기 때문에 recoverability가 보장됩니다.
    • write-lock을 commit/rollback될 때 반환합니다.
  • strong strict 2PL(SS2PL)
    • strict schedule을 보장하는 SPL입니다. 그래서 이 프로토콜도 recoverability가 보장됩니다.
    • read-lock/write-lock모두 commit/rollback될 때 반환됩니다.
    • S2PL보다 구현이 쉽지만 read-lock도 가져가기 때문에 다른 트랜잭션이 기다리는 시간이 길어집니다.

인덱스

인덱스가 무엇인가요?

인덱스란 조건을 만족하는 튜플을 빠르게 조회하기 위해서 사용하는 자료구조입니다.

인덱스를 왜 사용하나요?

특정 조건을 만족하는 데이터를 빠르게 찾기위해서 사용합니다.

일반적으로 인덱스는 수정이 잦은 테이블에서는 사용하지 않는것이 권장됩니다. 왜그럴까요?

인덱스는 정렬된 상태를 유지해야하기 때문에 수정이 일어나면 인덱스의 정렬을 위해 추가적인 작업이 필요합니다. 수정이라고 하면 삽입, 삭제, 업데이트가 있는데 삽입작업의 경우에는 새로운 인덱스를 추가해야합니다. 삭제작업은 인덱스를 삭제하는것이 아니라 사용하지 않는 다는 표시만 해두는 것이기 때문에 실제로 사용하는 데이터에 비해 인덱스 테이블의 사이즈가 비대해질 우려가 있습니다. 그리고 업데이트 작업은 기존에 있던 데이터를 삭제하고 새로운 데이터를 삽입하는 방식으로 구현되어 있기 때문에 앞에서 말한 삽입과 삭제의 단점이 모두 일어나게 됩니다.

그럼 수정이 잦아서 생기는 문제를 어떻게 해결할 수 있나요?

horizontal partitioning 을 통해서 row를 기준으로 테이블을 나누는 방법을 사용할 수 있습니다. 테이블의 데이터가 많을수록 B-Tree의 규모가 크고 조정하는데 시간이 걸리는 것이기 때문에 horizontal partitioning을 하면 테이블의 크기로 인해 처리시간이 조금씩 늘어나는 문제를 해결할 수 있습니다.

인덱스의 키값은 작을수록 좋은가요?

인덱스의 키값은 작을수록 좋습니다. 인덱스의 키값이 작아질수록 한 페이지에 들어가는 인덱스의 키가 늘어나기 때문입니다. B-Tree의 루트노드, 브랜치노드, 리프노드가 페이지 단위로 관리되기 때문에 인덱스의 키값이 작을수록 하나의 노드에 더 많은 키값을 담을 수 있게 되어 B-Tree의 깊이가 얕아지고 탐색시간이 줄어듭니다.

인덱스의 선택도란?

인덱스는 유니크한 키 값이 많을수록 검색대상이 줄어들기 때문에 빠르게 처리된다. 선택도(Cardinality)가 높을수록 좋다.

인덱스 레인지 스캔이란?

인덱스 레인지 스캔은 검색해야할 인덱스의 범위가 결정되었을 때 사용하는 방식입니다. 루트노드부터 시작해서 브랜치 노드를 거쳐 리프노드까지 찾아들어가고 그곳에서부터 리프노드의 레코드를 순서대로 읽는 방법입니다.

인덱스 레인지 스캔을 사용하면서 주의해야할 점?

인덱스의 리프노드에서 검색조건에 일치하는 건들은 데이터파일을 직접 읽어와야하는데 이때 랜덤IO가 발생합니다. 그래서 인덱스를 통해 데이터 레코드를 읽는 작업은 비용이 많이드는 작업이 됩니다.

인덱스 레인지 스캔의 과정을 설명해주세요
  1. 인덱스에서 조건을 만족하는 값이 있는 위치를 찾는다. (인덱스 탐색)
  2. 탐색된 위치부터 필요한 만큼 인덱스를 차례로 읽는다. (인덱스 스캔)
  3. 읽어들인 인덱스 키와 레코드 주소를 사용해서 레코드가 저장된 페이지를 가져오고 최종 레코드를 읽어온다.
인덱스 풀 스캔이란?

인덱스의 처음부터 끝까지 모두 읽는 방식을 인덱스 풀 스캔이라고 합니다.
인덱스 리프노드의 제일 앞 또는 뒤로 이동한 후 인덱스의 리프노드를 연결하는 연결리스트를 따라 처음부터 끝까지 스캔하는 방식입니다.

언제 인덱스 풀 스캔이 사용되나요?
  • 대표적으로 쿼리의 조건절에 사용된 컬럼이 인덱스의 첫번째 컬럼이 아닌 경우 사용됩니다.
  • 쿼리가 인덱스를 이루는 컬럼만으로 조건을 처리할 수 있는 경우.
인덱스 정순 스캔, 역순 스캔 무엇이 빠른가?

InnoDB 스토리지 엔진에서 정순 스캔과 역순 스캔의 차이는 페이지간의 양방향 연결고리를 통해 전진하느냐 후진하느냐의 차이만 있어 얼마 차이가 나지 않을 것이라고 생각할 수 있지만 실제 내부적으로는 정순스캔이 더 빠를수 밖에 없는 이유가 있습니다.

  • 페이지 잠금이 인덱스 정순 스캔(Forward Index Scan)에 적합한 구조이다.
  • 페이지 내에서 인덱스 레코드는 단방향으로만 링크를 가지는 구조이다.
DBMS는 인덱스를 어떻게 관리하나요?

일반적으로 B-Tree 를 사용해서 관리합니다.

B-Tree와 B+Tree에 대해서 설명해주세요
  • B-Tree는 탐색성능을 높이기 위해 균형있게 높이를 유지하는 밸런스 트리의 일종입니다. 모든 리프노드가 같은 레벨로 유지되도록 자동으로 밸런스롤 맞춰줍니다.
  • B+Tree는 B-Tree의 확장 개념으로 브랜치 노드에는 키만 담아두고 노드는 담지 않습니다. 오직 리프노드에만 키와 데이터를 저장하고 리프노드끼리는 연결리스트로 이어져있습니다.
왜 해시 테이블이 아니라 B-Tree를 주로 사용하나요?

해시 테이블은 키와 값의 쌍으로 데이터를 저장해서 데이터를 빠른시간에 검색할 수 있지만 동등(=) 연산에만 특화되어 있고, 실제로 쿼리를 사용할 때는 범위연산도 자주사용되기 때문에 적합하지 않습니다.

클러스터링 인덱스가 무엇인가?

PK가 비슷한 레코드끼리 묶어서 저장하는 것을 말합니다. 기본적으로 PK에 대해서만 적용되고, 테이블에 PK가 없다면 유니크 키를 기준으로 적용되는 등 기준이 정해져 있다.

클러스터링 인덱스가 B-Tree 인덱스와 다른 점은?

구조만 보면 클러스터링 인덱스와 B-Tree 인덱스가 비슷해보이지만 세컨더리 인덱스를 위한 B-Tree의 리프노드에는 레코드의 주소가 있는 반면 클러스터링 인덱스의 리프노드에는 레코드의 모든 컬럼이 같이 저장되어 있습니다. 클러스터링 테이블은 그 자체로 거대한 인덱스 구조로 관리됩니다.

클러스터링 인덱스의 장단점은?
  • 장점
    • 프라이머리 키로 검색할 때 처리 성능이 매우 빠르다. 특히 프라이머리 키를 범위검색하는 경우 매우 빠름.
    • 테이블의 모든 세컨더리 인덱스가 프라이머리 키를 가지고 있기 때문에 인덱스만으로 처리될 수 있는 경우가 많다. 이를 커버링 인덱스라 한다.
  • 단점
    • 테이블의 모든 세컨더리 인덱스가 클러스터링 키를 갖기 때문에 클러스터링 키의 값이 클수록 전체적으로 인덱스의 값이 커진다.
    • 세컨더리 인덱스를 통해 검색할 때 프라이머리 키로 한번 더 검색해야 하기 때문에 처리성능이 느리다.
클러스터링 인덱스를 사용할 때 주의해야할 점은?

PK의 크기가 커질수록 레코드당 필요한 인덱스의 크기가 커지기 때문에 키값을 신중하게 선택하는 것이 중요합니다.

커버링 인덱스가 무엇인가요?

인덱스가 쿼리에 필요한 모든 컬럼을 가지고 있는 것을 말합니다.

커버링 인덱스를 사용하면 왜 속도가 빨라지나요?

논 클러스터링 인덱스는 리프노드에 레코드의 주소를 가지고 있지 않고 연관된 PK값만 가지고 있습니다. 따라서 논 클러스터링 인덱스가 쿼리에 필요한 모든 컬럼을 가지고 있지 않다면 PK로 클러스터링 인덱스를 사용해 한번더 검색을 수행하여 데이터 블록에 접근해야합니다. 만약 논 클러스터링 인덱스가 쿼리에 필요한 모든컬럼을 가지고 있는 커버링 인덱스라면 이 과정이 생략될 수 있기 때문에 속도가 빨라집니다.

B-Tree가 무엇인가요?

B-Tree는 하나의 노드에 키값을 하나이상 저장할 수 있는 밸런스 트리입니다.

B-Tree의 데이터 삽입 시간복잡도는?
  • 데이터의 추가는 항상 리프노드에서 발생합니다.
  • 노드가 넘치면 가운데 키값을 기준으로 좌우 키들을 분할하고 가운데 키는 부모 노드로 승진시킵니다.
  • B-Tree는 모든 리프노드가 같은 레벨에 있는 밸런스트리이기 때문에 평균과 최악의 경우 모두 O(logN)의 시간복잡도를 가집니다.
B-Tree의 데이터 삭제에 대해서 설명해주세요.

B-Tree의 삭제도 항상 리프노드에서 이루어집니다. 키값을 삭제한 이후에 노드가 가지고 있는 키 값이 하나의 노드에서 가져야하는 최소한의 키의 갯수보다 적어졌다면 재조정합니다. 키의 수가 여유있는 형제의 지원을 받고, 형제가 여유가 없다면 부모의 지원을 받고 형제와 노드를 합치는 방법을 선택합니다. 이 방법을 거치고 부모에 문제가 있다면 그곳에서 다시 재조정합니다.

B-Tree 키값 삭제후 최소키보다 적을 때 형제의 지원을 받는 과정을 설명해주세요.

같은 부모를 가지는 노드 중에서 현재 노드보다 작은 값을 가지는 노드를 동생이라하고, 큰값을 가지는 노드를 형이라 합니다. 동생 노드에 여유가 있다면 동생 노드에서 가장 큰값을 부모로 올리고 부모가 원래 가지고 있던 키값을 현재 노드로 가져옵니다. 만약 동생이 여유가 없고 형이 여유가 있다면 형의 키값 중에서 가장 작은 키값을 부모로 올리고 원래 부모가 가지고 있던 값을 현재 노드로 가져옵니다.

internal 노드에서 데이터를 삭제해야한다면 어떻게 하나요?
  • internal 노드에 있는 데이터를 삭제하려면 리프노드에 있는 데이터와 위치를 바꾼 후 삭제합니다.
  • 리프노드에 있는 데이터 중 어떤 데이터와 위치를 바꾸어 줄 것인지가 이슈가 됩니다. 이 때는 삭제할 데이터의 선입자나 후임자와 위치를 바꾸어 줍니다.
    • 선임자: 나보다 작은 데이터 중에서 가장 큰 데이터
    • 후임자: 나보다 큰 데이터 중에서 가장 작은 데이터
왜 DB 인덱스로 B-Tree 계열을 사용하는건가요?

BST는 데이터가 삽입되는 순서에 따라서 노드가 한쪽으로만 몰리는 트리가 발생할 수 있기 때문에 최악의 경우 조회, 삽입, 삭제 시간이 O(N)이 될 수 있습니다. 그에 반해 B-Tree는 조회, 삽입, 삭제에 걸리는 시간이 평균시간과 최악의 시간 모두 O(logN)입니다.

밸런스 트리에는 AVL Tree나 레드블랙 트리도 있는데, 왜 인덱스로 B-Tree를 사용하는 건가요?

레드블랙 트리나, AVL Tree같은 바이너리 서치트리 계열의 트리는 자식의 수가 2개로 한정되어 있지만, B-Tree는 자식의 갯수가 한정되어 있지않아 좀더 빠르게 탐색범위를 좁힐수 있습니다. 탐색범위를 좁힌다는 것은 Secondary Storage에 접근하는 횟수가 줄어든다는 것을 의미합니다. 그래서 똑같은 데이터를 저장하더라도 B-Tree 가 Secondary Storage에 더 적게 접근하면서도 빨리 리프노드까지 데이터를 찾을 수 있습니다.

또 노드가 가질 수 있는 데이터의 수에도 차이가 있습니다. AVL Tree 같은 경우는 노드당 1개의 데이터만 가질 수 있지만, B-Tree의 경우에는 노드가 더많은 데이터를 가질 수 있기 때문에 블록단위의 저장공간 활용도가 더 좋습니다.

Hash Index를 쓰는건 어떤가요?

해시 인덱스를 사용하면 삽입/삭제/조회 시간이 상수시간이기 때문에 확실히 이점이 있습니다. 하지만 동등비교만 가능하고 범위연산이 불가능하다는 단점이 있습니다. 범위비교나 정렬할 일이 없고 앞으로도 동등조건으로 조회만 할것이라는 확신이 있다면 해시인덱스를 사용하는 것이 이점이 있습니다. 하지만 그럴일은 거의 없기 때문에 일반적으로 B-Tree를 사용합니다.

정규화

정규화가 무엇인가요?

데이터 중복과 삽입/수정/삭제 이상현상을 최소화하기 위해 normal form에 따라 RDB를 구성하는 과정을 말합니다.

정규화되지 않았을 때 어떤 이상현상이 발생할 수 있나요?
  • 삽입 이상
    • 필요한 데이터를 삽입할 수 없는 경우가 발생합니다.
    • 예를 들어, 고객 테이블에 주소정보가 없는 고객을 추가할 수 없는 경우가 발생할 수 있습니다.
  • 삭제 이상
    • 의도하지 않은 데이터가 함께 삭제되는 경우
    • 고객 테이블에서 고객정보를 삭제하면서 주소정보도 함께 삭제되는 경우
  • 갱신 이상
    • 일부 데이터만 수정되어 데이터 불일치가 발생하는 경우
    • 고객 테이블에서 고객 이름을 수정하면서 주소 정보는 수정되지 않아 데이터 불일치가 발생할 수 있습니다.
역정규화가 무엇인가요?

테이블을 너무 많이 쪼개면 여러 테이블이 동시에 조인하게 되면서 성능이 느려지고, 관리도 힘들어지기 때문에 쪼갰던 테이블을 다시 합칠수도 있습니다. 이것을 역정규화라고 합니다.
DB를 설계할 때 과도한 조인중복데이터 최소화 사이에서 적정수준을 잘 선택해야합니다.

커넥션 풀

DBCP(데이터베이스 커넥션 풀)을 왜 사용하는가?
  • 백엔드 서버와 데이터베이스 서버는 보통 다른 서버에서 동작하기 때문에 쿼리를 요청하고 응답을 받는 것은 네트워크 통신이 필요합니다. TCP 프로토콜을 통해 서로 연결을 맺게 되는데 TCP는 연결지향적이기 때문에 연결을 맺을 때 3 way handshake, 연결을 끊을 때 4 way handshake등의 과정을 거쳐야합니다. 매번 커넥션을 열고 닫을 때마다 비용이 발생합니다. 문제는 백엔드 서버에는 요청이 계속해서 들어오고, 각각의 API가 한번만 DB에 접근하는 것이 아니라 여러번 접근할 수도 있는 것이기 때문에 그때마다 매번 새로운 커넥션을 열고닫는 과정은 시간적인 비용이 너무 많이 발생합니다. 결국 이것은 서비스 성능에 좋지 않은 영향을 미치는데 이 문제를 해결하기 위해서 데이터베이스 커넥션 풀을 사용합니다.
DBCP가 무엇인가?

DB 커넥션을 미리 만들어 두고 연결된 커넥션들을 마치 pool처럼 관리하는 것을 말합니다. 요청이 오면 새롭게 커넥션을 맺는 것이 아니라 커넥션 풀에 있는 커넥션 중 사용하지 않는 것을 가져와 요청하는데 사용합니다. 커넥션을 다 사용하면 종료하는 것이 아니라 커넥션풀에 반환합니다.

파티셔닝, 샤딩, 레플리케이션

파티셔닝이란?

파티셔닝은 데이터베이스 테이블을 더 작은 테이블로 나누는 방식을 말합니다.

vertical partitioning이란?
  • Column을 기준으로 테이블을 나누는 방식입니다.
  • 정규화 과정에서 테이블을 나누는 것도 일종의 Vertical Partitioning이라고 합니다.
vertical partitioning을 왜 사용하나요?
  • 이미 정규화된 테이블이라도 퍼포먼스를 높이기 위해서 사용합니다.
    • 테이블의 컬럼 일부만 조회한다고 해도 테이블에 있는 데이터를 모두 메모리로 가져온 다음에 필터링하게 됩니다.
    • 만약 사용하지 않는 부분이 큰 사이즈를 차지한다면 불필요한 IO 부담이 늘어나기 때문입니다.
  • 민감한 정보에 접근하지 못하도록 제약을 걸기 위해서
  • 자주사용하는 속성과 그렇지 않은 것으로 테이블을 나누기 위해서
horizontal partitioning이란?
  • row를 기준으로 테이블을 나누는 방식입니다.
horizontal partitioning을 왜 사용하나요?
  • 테이블의 데이터가 많아질수록 인덱스의 크기도 커지고 읽기/쓰기 시간도 늘어납니다.
  • 인덱스의 크기가 커진다는 것은 테이블에 읽기/쓰기 작업이 있을 때마다 인덱스에서 처리되는 시간도 늘어난다는 것을 의미합니다. 테이블에 데이터가 많을 수록 B-Tree의 규모도 커지기 때문에 조정하는데 시간이 더 걸립니다.
horizontal partitioning을 어떻게 수행하나요?
  • 가장 많이 사용되는 horizontal partitioning 방식은 hash function을 사용하는 방식입니다.
  • partition key가 될 속성을 정하고 키를 hash function에 통과시켜 나오는 결과로 테이블을 결정하는 방법입니다.
샤딩이 무엇인가요?
  • horizontal partitioning으로 나누어진 각 파티션들을 서로다른 DB 서버에 분산시키는 것을 말합니다.
  • 규모가 큰 서비스, 데이터가 많이 쌓이는 테이블, 트래픽이 많이 몰리는 테이블에 샤딩을 써서 파티션마다 독립된 DB서버를 할당해 트래픽을 분산시켜 DB서버의 부하를 낮추는데 사용합니다.
레플리케이션이란?

주 DB 서버로부터 계속 copy함으로써 복사본을 유지하는 보조 DB 서버를 두는 방법을 말합니다.

레플리케이션을 왜 하나요?
  • 주 DB 서버에 문제가 생기면 빠르게 보조 DB 서버를 사용하도록 처리할 수 있습니다.
  • 장애상황이 발생했을 때도 계속해서 서비스가 유지될수 있도록 해줍니다.
  • 또 대부분의 서비스는 읽기작업이 많고 쓰기 작업이 적기때문에 레플리케이션을 구성해서 읽기트래픽을 분산시킬때 사용하기도 합니다.

RDB와 NoSQL

RDB의 단점에 대해서 설명해주세요
  • RDB에서 새로운 컬럼을 추가하기 위해서는 스키마를 변경해주어야한다. 데이터가 많은 테이블에 대해서 스키마를 변경하는 작업은 상당히 부담스러운 작업이다.
  • RDB는 스키마에 맞춰서 데이터를 저장해야하기 때문에 확장성이 부족하다.
  • 정규화를 통해서 중복된 데이터의 저장을 막을 수 있다. 하지만 그로인해 여러 테이블의 JOIN연산이 필요해지고 성능이 하락된다.
  • RDB는 DB를 Scale-Out 하는 것에 유연하지 않다.
  • RDB가 트랜잭션의 ACID를 보장해준다는 것은 분명한 장점이다. 하지만 RDBMS가 ACID를 보장하기 위해서 DB 서버의 퍼포먼스를 일부 소모하기 때문에 전체적인 처리량이 떨어진다.
NoSQL이 무엇인가요?

관계형 데이터베이스의 전형적인 테이블 구조 대신, JSON 문서와 같은 하나의 데이터 구조안에 데이터를 보관하는 저장소를 말합니다.

NoSQL이 왜 필요한가요?

인터넷이 엄청나게 보급되면서 높은 처리량낮은 응답시간이 요구되었습니다. 거기다 다양한 사용자들이 다양한 데이터를 발생시키다보니 비정형 데이터가 증가하였습니다. 결과적으로 스키마라는 틀을 정해놓고 일정한 데이터만 저장하기에는 어려운 상황이 발생하였고, 이러한 상황에서 등장한것이 NoSQL입니다.

NoSQL의 특징에 대해서 설명해주세요
  • 유연한 스키마
    • RDB에서는 테이블을 만들때 스키마를 정해주어야하지만 NoSQL은 스키마를 정해두지 않고 데이터를 넣고 싶은 형태로 넣어줄 수 있습니다.
    • 유연하지만 그만큼 스키마의 관리를 개발자가 담당해야된다는 점이 부담된다.
  • 중복 허용(join 회피)
    • NoSQL에서는 중복된 데이터를 허용해서 JOIN이 발생하지 않도록 한다.
    • 중복을 허용하는 만큼 애플리케이션 레벨에서 중복된 데이터들이 최신 데이터를 유지할 수 있게 신경써야한다.
  • Scale-out
    • NoSQL은 계속해서 DB서버를 추가하는 것만으로 scale-out할 수 있는 데이터베이스이다.
    • 만약 RDB 였다면 각 테이블이 정규화되어 있을 것이고, 각 테이블을 분배해서 저장하게 된다. 여러 테이블이 각 서버에 흩어져 있으므로 조인해서 데이터를 가져오려면 네트워크 트래픽이 발생하는 등 어려운 점이 있다.

ACID의 일부를 포기하고 높은 처리량낮은 응답시간을 추구하는 것이 NoSQL의 철학이다. 하지만 금융시스템처럼 일관성이 중요한 환경에서는 아직 사용하기 조심스럽다.

This post is licensed under CC BY 4.0 by the author.