Home 면접을위한 CS 지식. Chapter4-Database
Post
Cancel

면접을위한 CS 지식. Chapter4-Database

데이터베이스의 기본

  • 데이터베이스는 일정한 규칙, 규약을 통해 구조화되어 저장되는 데이터의 모음이다.
  • 해당 데이터베이스를 제어, 관리하는 통합 시스템을 DBMS라고 하며, 데이터 베이스 안에 있는 데이터들은 특정 DBMS마다 정의된 쿼리 언어를 통해 삽입, 삭제, 수정, 조회 등을 수행할 수 있다.
  • 또한 데이터 베이스는 실시간 접근과 동시 공유가 가능하다.

엔터티(entity)

  • 언터티는 사람, 장소, 물건, 사건, 개념 등 여러 개의 속성을 지닌 명사를 의미한다.

약한 엔터티와 강한 엔터티

  • 엔터티는 약한 엔터티와 강한 엔터티로 나뉜다.
  • 예를 들어 A가 혼자서는 존재하지 못하고 B의 존재 여부에 따라 종속적이라면 A는 약한 엔터티이고, B는 강한 엔터티이다.

릴레이션(relation)

  • 데이터베이스에서 정보를 구분하여 저장하는 기본 단위이다.
  • 엔터티에 관한 데이터를 데이터베이스는 릴레이션 하나에 담아서 관리한다.
  • 릴레이션은 관계형 데이터 베이스에서는 테이블이라고 하며, NoSQL 데이터베이스에서는 컬렉션이라고 한다.

테이블과 컬렉션

  • 데이터베이스의 종류는 크게 관계형 데이터베이스와 NoSQL 데이터베이스로 나눌 수 있다.
  • 이 중 대표적인 관계형 데이터 베이스인 MySQL과 대표적인 NoSQL 데이터베이스인 MongoDB로 예시는 아래와 같다.
    • MySQL : 레코드 - 테이블 - 데이터베이스
    • MongoDB : 도큐먼트 - 컬렉션 - 데이터베이스

속성(attribute)

  • 릴레이션에서 관리하는 구체적이며 고유한 이름을 갖는 정보이다.
  • 예를 들어 ‘차’ 엔터티의 속성은 아래와 같다.
    • 차 넘버, 바퀴 수, 차 색깔, 차종

도메인(domain)

  • 도메인이란 릴레이션에 포함된 각각의 속성들이 가질 수 있는 값의 집합을 말한다.
  • 예를 들어 성별이라는 속성이 있을 때 가질 수 있는 값은 [남, 녀]라는 집합이다.

필드와 레코드

  • 데이터베이스에서 필드와 레코드로 구성된 테이블을 만들어 관리한다.

관계

  • 여러 개의 테이블이 있고 이러한 테이블은 서로의 관게가 정의되어 있다. 이러한 관계를 관계 화살표라 한다.

1:1 관계

  • 테이블을 두 개의 테이블로 나눠 테이블의 구조를 더 이해하기 쉽게 만들어 준다.

1:N 관계

  • 한 개체가 다른 많은 개체를 포함하는 관계를 말한다.

N:M 관계

  • N:M은 테이블 두 개를 직접적으로 연결해서 구축하지 않고, 1:N, 1:M이라는 관계를 갖는 테이블 두개로 나눠서 설정한다.

  • 테이블 간의 관계를 조금 더 명확하게 하고 테이블 자체의 인텍스를 위해 설정된 장치로 기본키, 외래키, 후보키, 슈퍼키, 대체키가 있다.
  • 슈퍼키는 유일성이 있고 그 안에 포함된 후보키는 최소성까지 갖춘 키이다.
  • 후보키 중에 기본키로 선택되지 못한 키는 대체키가 된다.
  • 유일성은 중복되는 값은 없으며, 최소성은 필드를 조합하지 않고 최소 필드만 써서 키를 형성할 수 있는 것을 말한다.

기본키(Primary Key)

  • 기본키는 줄여서 PK라고 부르며, 유일성과 최소성을 만족하는 키다.
  • 기본키는 자연키와 인조키 중에 골라 설정한다.
    • 자연키 :중복된 값들을 제외하며 중복되지 않는 것을 ‘자연스레’뽑다가 나오는 키를 자연키라고 한다. 자연키는 언젠가는 변하는 속성을 가진다.
    • 인조키 : 인위적으로 유저 아이디를 부여하여 생겨난 고유 식별자를 말한다. 자연키와 대도적으로 변하지 않는다. 따라서 보통 기본키는 인조키로 설정한다.

외래키(foreign key)

  • 외래키는 FK라고도 하며, 다른 테이블의 기본키를 그대로 참조하는 값으로 개체와의 관계를 식별하는 데 사용한다.

ERD와 정규화 과정

  • ERD(Entity Relationship Diagram)는 데이터베이스를 구축할 때 가장 기초적인 뼈대 역할을 하며, 릴레이션 간의 관계들을 정의한 것이다.
  • 서비스를 구축할 때 가장 먼저 신경 써야 할 부분이다.

데이터베이스 이상 현상(anomaly)

  • 데이터의 중복, 불일치, 손실 등으로 인해 데이터의 무결성이 깨지는 현상이다.
  • 삽입 이상(Insertion Anomaly)
    • 불필요한 데이터를 함께 삽입해야 하는 문제
    • 예: 학생 정보를 저장할 때, 수강 신청 정보가 없어도 학과 정보를 반복해서 입력해야 하는 경우
  • 삭제 이상(Deletion Anomaly)
    • 튜플 삭제 시 연관된 다른 정보까지 함께 삭제되는 문제
    • 예: 학생 정보를 삭제할 때, 해당 학생이 속한 학과의 유일한 학생이라면 학과 정보까지 손실되는 경우
  • 수정 이상(Update Anomaly)
    • 중복 데이터의 일부만 수정해 데이터 불일치가 발생하는 문제
    • 예: 학과명을 변경할 때, 일부 튜플만 수정해 학과명이 일치하지 않게 되는 경우

정규화 과정

  • 정규화 과정은 릴레이션 간의 잘못된 종속 관계로 인해 데이터베이스 이상 현상이 일어나서 이를 해결하거나, 저장 공간을 효율적으로 사용하기 위해 릴레이션을 여러 개로 분리하는 과정이다.

  • 정규화 과정은 정규형 원칙을 기반으로 정규형을 만들어가는 과정이며, 정규화된 정도는 정규형(NF, Normal Form)으로 표현한다.
  • 기본 정규형인 제1 정규형, 제2 정규형, 제3 정규형, 보이스/코드 정규형이 있고, 고급 정규형인 제4 정규형, 제5 정규형이 있다.

정규형 원칙

  • 정규형의 원칙이란 같은 의미를 표현하는 릴레이션이지만 좀 더 좋은 구조로 만들어야 하고, 자료의 중복성은 감소해야 하고, 독립적인 관계는 별개의 릴레이션으로 표현해야 하며, 각각의 릴레이션은 독립적인 표현이 가능해야 하는 것을 말한다.

제1정규형(First Normal Form, 1NF):

  • 모든 속성의 도메인이 원자값(atomic value)만을 포함해야 합니다. 즉, 각 속성은 더 이상 분해할 수 없는 단일 값을 가져야 한다.
  • 같은 릴레이션에 중복된 튜플이 존재하지 않아야 한다.
  • 각 튜플은 유일한 식별자(primary key)를 가져야 한다.
  • 예를 들어, 학생 정보 테이블에서 ‘주소’ 속성이 ‘도시, 국가’와 같이 여러 값을 포함한다면 1NF를 만족하지 않는다. 이를 ‘도시’, ‘국가’로 분리해야 1NF를 충족할 수 있다.

제2정규형(Second Normal Form, 2NF):

  • 1NF를 만족해야 한다.
  • 모든 비주요 속성(non-prime attribute)이 후보 키(candidate key)에 완전 함수 종속(fully functional dependency)이어야 한다.
  • 즉, 부분 함수 종속(partial functional dependency)이 존재하지 않아야 한다.
  • 예를 들어, ‘학생, 과목, 교수, 성적’ 테이블에서 ‘성적’이 ‘학생, 과목’ 조합에 종속되고, ‘교수’가 ‘과목’에만 종속된다면 2NF를 만족하지 않는다. 이 경우 ‘학생, 과목, 성적’과 ‘과목, 교수’로 테이블을 분리해야 2NF를 충족할 수 있다.

제3정규형(Third Normal Form, 3NF):

  • 2NF를 만족해야 한다.
  • 모든 비주요 속성이 기본 키(primary key)에 이행적 함수 종속(transitive functional dependency)이 아니어야 한다.
  • 즉, 비주요 속성 간의 종속 관계가 존재하지 않아야 한다.
  • 예를 들어, ‘학생, 학과, 학과장’ 테이블에서 ‘학과장’이 ‘학과’에 종속되고, ‘학과’가 ‘학생’에 종속된다면 3NF를 만족하지 않는다. 이 경우 ‘학생, 학과’와 ‘학과, 학과장’으로 테이블을 분리해야 3NF를 충족할 수 있다.

보이스/코드 정규화(BCNF)

  • BCNF(Boyce-Codd Normal Form)는 제3정규형(3NF)보다 더 강력한 정규화 단계로, 함수 종속성(functional dependency)과 관련된 이상 현상을 추가로 제거한다.

  • BCNF의 조건:

    • 릴레이션이 3NF를 만족해야 한다.
    • 모든 결정자가 후보 키여야 한다. 즉, X → Y (X가 Y를 함수적으로 결정)인 함수 종속성에서 X는 반드시 후보 키여야 한다.
  • 예시:

    • 학생(학번, 이름, 학과, 지도교수)의 릴레이션이 있다고 가정한다. 이 릴레이션에는 다음과 같은 함수 종속성이 존재한다:
    • 학번 → 이름, 학과, 지도교수
    • 학과 → 지도교수
  • 이 릴레이션은 3NF를 만족하지만, BCNF는 만족하지 않는다. 왜냐하면 ‘학과 → 지도교수’에서 ‘학과’가 후보 키가 아니기 때문이다.
  • 이 경우 ‘학과’ 속성이 ‘지도교수’를 결정하므로, 이상 현상이 발생할 수 있다.

  • BCNF를 만족하기 위해서는 릴레이션을 분해해야 한다.:

    • 학생(학번, 이름, 학과)
    • 학과_지도교수(학과, 지도교수)
  • 각 정규형은 이전 단계의 정규형을 포함하며, 차례로 만족해야 한다.
  • 높은 단계의 정규형을 충족할수록 데이터의 중복이 감소하고 종속성이 줄어들어 이상 현상을 방지할 수 있다.
  • 하지만 지나친 정규화는 테이블의 수를 증가시키고 조인 연산의 비용을 높일 수 있으므로, 상황에 맞게 적절한 수준의 정규화를 적용하는 것이 중요하다.

트랜잭션과 무결성

트랜잭션(transaction)

  • 트랜잭션은 하나의 논리적 기능을 수행하기 위한 작업의 단위를 말한다.
    • 데이터베이스에서는 여러 개의 쿼리들을 하나로 묶는 단위를 말한다.
  • 이에 대한 특징은 원자성, 일관성, 독립성, 지속성이 있다. 이를 줄여서 ACID 특징이라고 한다.

원자성(atomicity)

  • “All or Nothing”
  • 트랜잭션과 관련된 일이 모두 수행되었거나 되지 않았거나를 보장하는 특징이다.
  • 예를 들어 트랜잭션을 커밋했는데, 문제가 발생하여 롤백하는 경우 그 이후에 모두 수행되지 않음을 보장하는 것을 말한다.
  • 트랜잭션 단위로 여러 로직들을 묶을 때 외부 API를 호출하는 것이 존재해서는 안된다.
    • 만약 존재한다면 롤백이 일어났을 때 어떻게 해야 할 것인지에 대한 해결 방법이 있어야하고, 트랜잭션 전파를 신경써서 관리해야 한다.

커밋과 롤백

  • 커밋(commit)은 여러 쿼리가 성공적으로 처리되었다고 확정하는 명령어이다.
  • 트랜잭션 단위로 수행되며 변경된 내용이 모두 영구적으로 저장되는 것을 말한다.
  • ‘커밋이 수행되었다’ -> ‘하나의 트랜잭션이 성공적으로 수행되었다.’
  • 롤백(roll back)이란 트랜잭션으로 처리한 하나의 묶음 과정을 일어나기 전으로 돌리는 일(취소)를 말한다.

트랜잭션 전파

  • 트랜잭션을 수행할 때 커넥션 단위로 수행하기 때문에 커넥션 객체를 넘겨서 수행해야 한다.
  • 하지만 이를 매번 넘겨주기는 번거롭다. 때문에 여러 트랜잭션 관련 메서드의 호출을 하나의 트랜잭션에 묶이도록 하는 것을 트랜잭션 전파라고 한다.

일관성(consistency)

  • 일관성은 ‘허용된 방식’으로만 데이터를 변경해야 하는 것을 의미한다.
  • 데이터 베이스에 기록된 모든 데이터는 여러 가지 조건, 규칙에 따라 유효함을 가져야 한다.

격리성(isolation)

  • 격리성은 트랜잭션 수행 시 서로 끼어들지 못하는 것을 말한다.
  • 복수의 병렬 트랜직션은 서로 격리되어 마치 순차적으로 실행되는 것처럼 작동되어야 하고, 데이터 베이스는 여러 사용자가 같은 데이터에 접근할 수 있어야 한다.
  • 하지만 단순하게 순차 처리를 하게 된다면 성능이 떨어지는 문제가 발생한다.
  • 이러한 이유로 격리성은 여러개의 격리 수준으로 나뉘어 격리성을 보장한다.

격리 수준

  • 트랜잭션의 격리 수준(Isolation Level)은 동시에 실행되는 트랜잭션 간의 데이터 일관성과 격리성을 결정하는 중요한 요소이다. 격리 수준은 낮은 수준에서 높은 수준까지 다음과 같이 분류된다.
  1. Read Uncommitted (레벨 0):
  • 다른 트랜잭션에서 커밋되지 않은 데이터를 읽을 수 있다.
  • Dirty Read, Non-Repeatable Read, Phantom Read 문제가 발생할 수 있다.
  • 데이터 일관성이 보장되지 않아 거의 사용되지 않는다.
  1. Read Committed (레벨 1):
  • 커밋된 데이터만 읽을 수 있습니다. Dirty Read는 방지된다.
  • 트랜잭션 내에서 동일한 쿼리를 실행해도 결과가 다를 수 있다. (Non-Repeatable Read)
  • 트랜잭션 도중 새로운 데이터가 삽입되어 쿼리 결과에 포함될 수 있다. (Phantom Read)
  • 대부분의 DBMS에서 기본적으로 사용되는 격리 수준이다.
  1. Repeatable Read (레벨 2):
  • 트랜잭션 내에서 한 번 읽은 데이터를 반복해서 읽어도 같은 결과를 보장한다. Non-Repeatable Read를 방지한다.
  • 트랜잭션 도중 수정된 데이터는 트랜잭션이 시작되기 전의 상태로 보인다.
  • 새로운 데이터가 삽입되는 Phantom Read 문제는 여전히 발생할 수 있다.
  • MySQL의 InnoDB 스토리지 엔진에서 기본적으로 사용되는 격리 수준다.
  1. Serializable (레벨 3):
  • 가장 높은 수준의 격리성을 제공합니다. Dirty Read, Non-Repeatable Read, Phantom Read를 모두 방지한다.
  • 트랜잭션이 순차적으로 실행되는 것처럼 동작한다.
  • 동시성이 크게 떨어지고 성능 저하가 발생할 수 있다.
  • 데이터 일관성이 매우 중요한 경우에 사용된다. (예: 금융 트랜잭션)

  • 각 격리 수준은 동시성과 데이터 일관성 사이의 트레이드오프 관계에 있다.
  • 격리 수준이 높을수록 데이터 일관성은 보장되지만, 동시성이 떨어지고 성능이 저하될 수 있다.
  • 반면, 격리 수준이 낮을수록 동시성은 향상되지만 데이터 일관성 문제가 발생할 수 있다.

  • 적절한 격리 수준을 선택하는 것은 애플리케이션의 요구사항과 데이터 일관성의 중요성에 따라 결정해야 한다. 대부분의 경우 Read Committed나 Repeatable Read 수준으로 충분하지만, 데이터 일관성이 매우 중요한 경우에는 Serializable 수준을 고려할 수 있다.

격리 수준에 따라 발생하는 현상

  • 팬턺 리드(phantom read) : 한 트랜잭션 내에서 동일한 쿼리를 보냈을 때 해당 조회 결과가 다른 경우이다.
  • 반복 가능하지 않은 조회(non-repeatable read) : 한 트랜잭션 내의 같은 행에 두 번 이상 조회가 발생했는데, 그 값이 다른 경우를 가리킨다.
    • 팬턺 리드와 다른 점은 반복 가능하지 않은 조회는 행 값이 달라질 수도 있는데, 팬텀 리드는 다른 행이 선택될 수 있다는 것을 의미한다.
  • 더티 리드(dirty read) : 한 트랜잭션이 실행 중일 때 다른 트랜잭션에 의해 수정되었지만 아직 ‘커밋되지 않은’행의 데이터를 읽을 수 있을 때 발생한다.

지속성(durability)

  • 성공적으로 수행된 트랜잭션은 영원히 반영되어야 하는 것을 의미한다.
  • 이는 데이터베이스에 시스템 장애가 발생해도 원래 상태로 복구하는 회복 기능이 있어야 함을 뜻하며, 데이터베이스는 이를 위해서 체크섬, 저널링, 롤백 등의 기능을 제공한다.
    • 체크섬 : 중복 검사의 한 형태로, 오류 정정을 통해 송신된 자료의 무결성을 보호하는 단순하 방법
    • 저널링 : 파일 시스템 또는 데이터베이스 시스템에서 변경 사항을 반영(commit)하기 전에 로깅하는 것, 트랜잭션 등 변경 사항에 대한 로그를 남기는 것

무결성

  • 무결성이란 데이터의 정확성, 일관성, 유효성을 유지하는 것을 말하며, 무결성이 유지 되어야 데이터베이스에 저장된 데이터 값과 그 값에 해당하는 현실 세계의 실제 값이 일치하는지에 대한 신뢰가 생긴다.
  • 개체 무결성 : 기본키로 선택된 필드는 빈 값을 허용하지 않는다.
  • 참조 무결성 : 서로 참조 관계에 있는 두 테이블의 데이터는 항상 일관된 값을 유지해야 한다.
  • 고유 무결성 : 특정 속성에 대해 고유한 값을 가지도록 조건이 주어진 경우 그 속성 값은 모두 고유한 값을 가진다.
  • NULL 무결성 : 특정 속성 값에 NULL이 올 수 어벗다는 조건이 주어진 경우 그 속성 값은 NULL이 될 수 없다는 제약 조건이다.

데이터베이스의 종류

관계형 데이터베이스

  • 행과 열을 가지는 표 형식 데이터를 저장하는 형태의 데이터베이스를 가리키며 SQL이라는 언어를 써서 조작한다.
  • MySQL, PostgreSQL, 오라클, SQL Server, MSSQL 등이 있다
    • 참고로 관계형 데이터 베이스의 경우 표준 SQL을 지키긴 하지만, 각각의 제품에 특화시킨 SQL을 사용한다.
    • 예를 들어 오라클의 경우 PL/SQL, SQL Server의 경우 T-SQL

MySQL

  • 대부분의 운영체제와 호환되며 현재 가장 많이사용하는 데이터베이스이다.
  • C, C++로 만들어졌으며 MyISAM 인덱스 압축 기술, B-트리 기반의 인덱스, 스레드 기반의 메모리 할당 시스템, 매우 빠른 조인, 최대 64개의 인덱스를 제공한다.
  • 대용량 데이터베이스를 위해 설계되었고 롤백, 커밋, 이중 암호 지원 보안 등의 기능을 제공한다.
  • 모듈식 아키텍처로 쉽게 스토리지 엔진을 바꿀 수 있으며 데이터 웨어하우징, 트랜잭션 처리, 고가용성 처리에 강점을 두고 있다.
  • 스토리지 엔진 위에는 커넥터 API 및 서비스 계층을 통해 MySQL 데이터베이스와 쉽게 상호 작용할 수 있다.
  • 쿼리 캐시를 지원하기 때문에 사용자가 작성한 쿼리가 캐시에 있는 쿼리와 동일하면 서버가 빠르게 응답해줄 수 있다.

PostgreSQL

  • MySql 다음으로 개발자들이 선호하는 데이터베이스 기술로 널리 인정받았다.
  • 디스크 조각이 차지하는 영역을 회수할 수 있는 장치인 VACUUM이 특징이다.
  • 최대 테이블의 크기는 32TB이다.
  • SQL뿐만 아니라 JSON을 이용해서 데이터에 접근할 수 있다.
  • 지정 시간에 복구하는 기능, 로깅, 접근 제어, 중첩된 트랜잭션, 백업 등을 할 수 있다.

NoSQL 데이터 베이스

  • SQL을 사용하지 않는 데이터베이스를 말한다. 대표적으로 MongoDB와 redis가 있다.

MongoDB

  • JOSN을 통해 데이터에 접근할 수 있고, Binary JSON(BSON) 형태로 데이터가 저장된다.
  • 와이어드 타이거 엔진이 기본 스토리지 엔진으로 장착된 키-값 데이터 모델에서 확장된 도큐먼트 기반의 데이터베이스이다.
  • 확장성이 뛰어나며 빅데이터를 저장할 때 성능이 좋고, 고가용성과 샤딩, 레플리카셋을 지원한다.
  • 스키마를 정해 놓지 않고 데이터를 삽입할 수 있기 때문에 다양한 도메인의 데이터베이스를 기반으로 분석하거나 로깅 등을 구현할 때 강점을 보인다.
  • MongoDB는 도큐먼트를 생성할 때 마다 다른 컬렉션에서 중복값을 지니기 힘든 유니크한 값인 ObjectID가 생성된다.
    • ID는 타임스탬프 + 랜덤값 + 카운터로 이루어져 있다

Redis

  • 인메모리 데이터베이스이자 키-값 데이터 모델 기반의 데이터베이스이다.
  • 기본적인 데이터 타입은 문자열이며 최대 512MB까지 저장할 수 있다.
  • 이외에도 set, hash 등을 지원한다.
  • pub/sub 기능을 통해 채팅 시스템, 다른 데이터베이스 앞단에 두어 사용하는 캐싱 계층, 단순한 키-값이 필요한 세션 정보 관리, 정렬된 셋(sorted set) 자료 구조를 이용한 실시간 순위표 서비스에 사용한다.

인덱스

  • 인덱스는 데이터를 빠르게 찾을 수 있는 하나의 장치이다.

B-트리

B-tree-img

  • 인덱스는 보통 B-트리라는 자료 구조로 이루어져 있다.
  • 이는 루트 노드, 리프 노드, 브랜치 노드(루트와 리프 노드 사이)로 나뉜다.
  • 특징
    • 각 노드는 여러 개의 키(key)와 자식 포인터를 가진다.
    • 노드의 키 개수를 k라고 할 때, 자식 포인터의 개수는 k+1이다.
    • 루트 노드를 제외한 모든 내부 노드는 최소 ⌈m/2⌉개의 키를 가진다. (m은 차수(order)로, 노드가 가질 수 있는 최대 키의 개수이다.)
    • 루트 노드는 적어도 1개의 키를 가진다. (트리가 비어있지 않은 경우)
    • 모든 리프 노드는 같은 레벨에 있다.
    • 노드 내의 키는 오름차순으로 정렬되어 있다.
    • 각 키의 왼쪽 서브트리에는 해당 키보다 작은 값이, 오른쪽 서브트리에는 해당 키보다 큰 값이 저장된다.
  • 트리의 탐색은 맨 위 루트 노드부터 탐색이 일어나며 브랜치 노드를 거쳐 리프 노드까지 내려온다.
  • 예를 들어 키 14를 찾을 경우
    • ‘14보다 같거나 클 때까지’를 기반으로 처음 루트노드에서부터 내려와 리프노드인 14에 도달하는 것을 볼 수있다.

인덱스가 효율적인 이유와 대수확장성

  • 인덱스가 효율적인 이유는 효율적인 단계를 거쳐 모든 요소에 접근할 수 있는 균형 잡힌 트리 구조와 트리 깊이의 대수확장성 때문이다.
  • 대수확장성 : 트리 깊이가 리프 노드 수에 비해 매우 느리게 성장하는 것을 의미한다.
    • 기본적으로 인덱스가 한 깊이씩 증가할 때마다 최대 인덱스 항목의 수는 4배씩 증가한다.
    • 대략 depth 10으로 100만개의 레코드를 검색할 수 있다. 실제로는 더 효율적이다.

인덱스 만드는 방법

  • 인덱스를 만드는 방법은 데이터베이스마다 다르며 MySQL과 MongoDB를 기준으로 설명한다.

MySQL

  • MySQL의 경우 클러스터형 인덱스와 세컨더리 인덱스가 있으며, 클러스터형 인덱스는 테이블당 하나를 설정할 수 있다.
  • primary key 옵션으로 기본키를 만들면 클러스터형 인덱스를 생성할 수 있고, 기본키로 만들지 않고 unique not null 옵션을 붙이면 클러스터형 인덱스로 만들 수 있다.
  • create index...명령어 기반으로 만들면 세컨더리 인덱스를 만들 수 있다.
  • 하나의 인덱스만 생성할 것이라면 클러스터형 인덱스를 만드는 것이 세컨더리 인덱스를 만드는 것보다 성능이 좋다.
  • 세컨더리 인덱스는 보조 인덱스로 여러 개의 필드 값을 기반으로 쿼리를 많이 보낼 때 생성해야 하는 인덱이다.

MongoDB

  • MongoDB의 경우 도큐먼트를 만들면 자동으로 ObjectID가 형성되며, 해당 키가 기본키로 설정된다.
  • 그리고 세컨더리키도 부가적으로 설정하여 기본키와 세컨더리키를 같이 쓰는 복합 인덱스를 설정할 수 있다.

인덱스 최적화 기법

  • 인덱스 최적화 기법은 데이터베이스마다 대동소이하다.
    • MongoDB를 기반으로 인덱스 최적화 기법을 설명한다.
  1. 인덱스는 비용이다.
    • 인덱스는 두 번 탐색하도록 강요한다. 인덱스 리스트, 컬렉션 순으로 탐색을 하기 때문이며, 관련 읽기 비용이 들게 된다.
    • 또한 컬렉션이 수정되었을 때 인덱스도 수정되어야 한다.
      • 이때 B-트리의 높이를 균형 있게 조절하는 비용도 들고, 데이터를 효율적으로 조회할 수 있도록 분산시키는 비용도 들게 된다.
    • 그렇기 때문에 쿼리에 있는 필드에 이덱스를 무작정 다 설정하는 것은 답이 아니다.
    • 또한 컬렉션에서 가져와야 하는 양이 많을수록 인덱스를 사용하는 것은 비효율적이다.
  2. 항상 테스팅하라
    • 인덱스 최적화 기법은 서비스 특징에 따라 달라진다.
    • 서비스에서 사용하는 객체의 깊이, 테이블의 양 등이 다르기 때문이다.
    • 그렇기 때문에 항상 테스팅하는 것이 중요하다.
    • explain() 함수를 통해 인덱스를 만들고 쿼리를 보낸 이후에 테스팅을 하며 걸리는 시간을 최소화 해야한다.
  3. 복합 인덱스는 같음, 정렬, 다중 값, 카디널리티 순이다.
    • 보통 여러 필드를 기반으로 조회를 할 때 복합 인덱스를 생성하는데, 이 인덱스를 생성할 때는 순서가 있고 생성 순서에 따라 인덱스 성능이 달라진다.
    • 같음, 정렬, 다중 값, 카디널리티 순으로 생성해야 한다.
      1. equal 관련 쿼리가 있다면 제일 먼저 인덱스로 설정해야 한다.
      2. 정렬에 쓰는 필드라면 그 다음 인덱스로 설정한다.
      3. 다중 값을 출력해야 하는 필드, 즉 쿼리 자체가 >, < 등 많은 값을 출력해야 하는 쿼리에 쓰는 필드라면 나중에 인덱스를 설정한다.
      4. 유니크한 값의 정도를 카디널리티라고 한다. 이 카디널리티가 높은 순서를 기반으로 인덱스를 생성해야 한다.

조인의 종류

  • 조인(join)이란 하나의 테이블이 아닌 두 개 이상의 테이블을 묶어서 하나의 결과물을 만드는 것을 말한다.
  • MySQL에서는 JOIN이라는 쿼리로, MongoDB에서는 lookup이라는 쿼리로 이를 처리할 수 있다.
    • 참고로 MongoDB의 lookup은 관계형 데이터베이스보다 성능이 떨어진다.
    • 따라서 조인 작업이 많을 경우 MongoDB보다는 관계형 데이터베이스를 써야한다.
  • 내부 조인(inner join) : 왼쪽 테이블과 오른쪽 테이블의 두 행이 모두 일치하는 행이 있는 부분만 표기한다. (교집합)
  • 왼쪽 조인(left outer join) : 왼쪽 테이블의 모든행이 결과 테이블에 표기된다.(오른쪽 테이블에서 일치하는 항목이 없다면 NULL 값이 포함됨)
  • 오른쪽 조인(right outer join) : 왼쪽 조인의 반대 방향
  • 합집합 조인(full outer join) : 두 개의 테이블을 기반으로 조인 조건에 만족하지 않는 행까지 모두 표기한다.

조인의 원리

  • 조인들은 조인의 원리인 중접 루프 조인, 정렬 병합 조인, 해시 조인에 의해 일어난다.
  • 앞서 설명한 조인의 종류는 이 원리를 기반으로 조인하는 것이다.

중첩 루프 조인(NLJ, Nested Loop Join)

  • 중첩 for문과 같은 원리로 조건에 맞는 조인을 하는 방법이며, 랜덤 접근에 대한 비용이 많이 증가하므로 대용량의 테이블에는 사용하지 않는다.
  • 예를 들어 ‘t1, t2 테이블을 조인한다’라고 했을 때 첫 번째 테이블에서 행을 한번에 하나 씩 읽고 그다음 테이블에서도 행을 하나씩 읽어 조건에 맞는 레코드를 찾아 결괏값을 반환한다.
  • 참고로 중첩 루프 조인에서 발전하여 조인할 테이블을 작은 블록으로 나눠서 블록 하나씩 조인하는 블록 중첩 루프 조인(BNL)이라는 방식도 있다.

정렬 병합 조인

  • 각각의 테이블을 조인할 필드 기준으로 정렬하고 정렬이 끝난 이후에 조인 작업을 수행하는 조인이다.
  • 조인할 때 쓸 적절한 인덱스가 없고 대용량의 테이블들을 조인하고 조인 조건으로 <, > 등의 범위 비교 연산자가 있을 때 쓴다.

해시 조인

  • 해시 조인은 해시 테이블을 기반으로 조인하는 방법이다.
  • 두 개의 테이블을 조인한다고 했을 때 하나의 테이블이 메모리에 온전히 들어간다면 보통 중첩 루프 조인보다 더 효율적이다.
  • 또한, 동등(=) 조인에서만 사용할 수 있다.
  • MySQL의 해시 조인 단계는 빌드 단계, 프로브 단계로 나뉜다.
    • 빌드 단계 : 입력 테이블 중 하나를 기반으로 메모리 내 해시 테이블을 빌드하는 단계이다.(더 작은 테이블을 빌드한다)
      • 조인에 사용되는 필드가 해시 테이블의 키로 사용된다.
    • 프로브 단계 : 레코드를 읽기 시작하며, 각 레코드에서 나머지 테이블의 id와 일치하는 레코드를 해시 테이블에서 찾아 결괏값을 반환한다.
    • 이를 통해 각 테이블은 한 번씩만 읽게 되어 중첩루프 조인보다 성능이 더 좋다.
This post is licensed under CC BY 4.0 by the author.

웹 프로그래밍 지식. JWT 토큰 인증

Docker 1. 도커 이해하기