ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 4장 데이터베이스
    Books/면접을 위한 CS 전공지식 노트 2023. 2. 2. 22:37

    4.1 데이터베이스의 기본

    - 데이터베이스(DB, DataBase)는 일정한 규칙, 혹은 규약을 통해 구조화되어 저장되는 데이터의 모음이다.

    - 해당 데이터베이스를 제어, 관리하는 통합 시스템을 DBMS(DataBase Management System)라고 하며,

    데이터베이스 안에 있는 데이터들은 특정 DBMS마다 정의된 쿼리 언어(query language)를 통해 삽입, 삭제, 수정, 조회 등을 수행할 수 있다.

    - 또한, 데이터베이스는 실시간 접근과 동시 공유가 가능하다.

    - 데이터베이스 위에 DBMS가 있고 그 위에 응용 프로그램이 있으며, 이러한 구조를 기반으로 데이터를 주고받는다.

    - 예를 들어 MySQL 이라는 DBMS가 있고 그위에 응용 프로그램에 속하는 Node.js나 php에서 해당 데이터베이스 안에 있는 데이터를 끄집어내 해당 데이터 관련 로직을 구축할 수 있다.

     

    4.1.1 엔터티

    - 엔터티(entity)는 사람, 장소, 물건, 사건, 개념 등 여러 개의 속성을 지닌 명사를 의미한다.

    - 예를 들어 회원이라는 엔터티가 있다고 해보자

        ㆍ회원은 이름, 아이디, 주소, 전화번호의 속성을 가진다.

        ㆍ물론 이보다 많은 속성이 있지만 서비스의 요구 사항에 맞춰 속성이 정해진다.

     

    약한 엔터티와 강한 엔터티

    - 엔터티는 약한 엔터티와 강한 엔터티로 나뉜다.

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

    - 방은 건물 안에만 존재하기 때문에 방은 약한 엔터티라고 할 수 있고 건물은 강한 엔터티라고 할 수 있다.

     

    4.1.2 릴레이션

    - 릴레이션(relation)은 데이터베이스에서 정보를 구분하여 저장하는 기본 단위이다.

    - 엔터티에 관한 데이터를 데이터베이스는 릴레이션 하나에 담아서 관리한다.

    - 예를 들어 회원이라는 엔터티가 데이터베이스에서 관리될 때 릴레이션으로 변화된 것을 볼 수 있다.

    - 릴레이션은 관계형 데이터베이스에서는 '테이블'이라고 하며, NoSQL 데이터베이스에서는 '컬렉션'이라고 한다.

     

    테이블과 컬렉션

    - 데이터베이스의 종류는 크게 관계형 데이터베이스와 NoSQL 데이터베이스로 나눌 수 있다.

    - 이 중 대표적인 관계형 데이터베이스인 MySQL과 대표적인 NoSQL 데이터베이스인 MongoDB를 예로 들면, 

        MySQL의 구조는 레코드-테이블-데이터베이스로 이루어져 있고

        MongoDB 데이터베이스의 구조는 도큐먼트-컬렉션-데이터베이스로 이루어져 있다.

    - 레코드가 쌓여서 테이블이 되고 테이블이 쌓여서 데이터베이스가 되는 것이다.

     

    4.1.3 속성

    - 속성(attribute)은 릴레이션에서 관리하는 구체적이며, 고유한 이름을 갖는 정보이다.

    - 예를 들어 '차'라는 엔터티의 속성을 뽑아보자

        ㆍ차 넘버, 바퀴 수, 차 색깔, 차종 등이 있을 것이다.

        ㆍ이 중에서 서비스의 요구 사항을 기반으로 관리해야 할 필요가 있는 속성들만 엔티티의 속성이 된다.

     

    4.1.4 도메인

    - 도메인(domain)이란 릴레이션에 포함된 각각의 속성들이 가질 수 있는 값의 집합을 말한다.

    - 예를 들어 성별이라는 속성이 있다면 이 속성이 가질 수 있는 값을 {남, 여}라는 집합이 된다.

     

    4.1.5 필드와 레코드

    - 앞에서 설명한 것들을 기반으로 데이터베이스에서 필드와 레코드로 구성된 테이블을 만들 수 있다.

    - 회원이라는 엔터티는 member라는 테이블로 속성인 이름, 아이디 등을 가지고 있으며 name, ID, address 등의 필드를 가진다.

    - 그리고 이 테이블에 쌓이는 행(row) 단위의 데이터를 레코드라고 한다.

    - 또한, 레코드를 튜플이라고도 한다.

    CREATE TABLE book(
        id INT NOT NULL AUTO_INCREMENT,
        title VARCHAR(255),
        author_id INT,
        publishing_year VARCHAR(255),
        genre VARCHAR(255),
        created_at DATETIME,
        updated_at DATETIME,
        PRIMARY KEY(id)
    );

     

    필드 타입

    - 필드는 타입을 갖는다.

    - 타입은 DBMS마다 다르며 이책에서는 MySQL 기준으로 설명하겠다.

    - 여러 가지 타입이 있고 대표적인 타입인 숫자, 날짜, 문자 타입에 대해 알아보자

     

    숫자 타입

    - 숫자 타입으로는 TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT 등이 있다.

    타입 용량(바이트) 최솟값(부호 있음) 최솟값(부호 없음) 최댓값(부호 없음) 최댓값(부호 있음)
    TINYINT 1 -128 0 127 255
    SMALLINT 2 -32768 0 32767 65535
    MEDIUMINT 3 -8388608 0 8388607 16777215
    INT 4 -2147483648 0 2147483647 4294967295
    BIGINT 8 -263 0 263-1 264-1

     

    날짜 타입

    - 날짜 타입으로는 DATE, DATETIME, TIMESTAMP 등이 있다.

    타입 용량(바이트) 사용 지원
    DATE 3 날짜 부분은 있지만 시간 부분이 없는 값에 사용 1000-01-01 ~ 9999-12-31
    DATETIME 8 날짜 및 시간 부분을 모두 포함하는 값에 사용 1000-01-01 00:00:00
    ~ 9999-12-31 23:59:59
    TIMESTAMP 4 날짜 및 시간 부분을 모두 포함하는 값에 사용 1970-01-01 00:00:01
    ~ 2038-01-19 03:14:07

    문자타입

    - 문자 타입으로는 CHAR, VARCHAR, TEXT, BLOB, ENUM, SET

     

    CHAR와 VARCHAR

    - CHAR 또는 VARCHAR 모두 그 안에 수를 입력해서 몇 자까지 입력할지 정한다.

    - 예를 들어 CHAR(30)이라면 최대 30글자까지 입력할 수 있다.

    - CHAR는 테이블을 생성할 때 선언한 길이로 고정되며 길이는 0에서 255 사이의 값을 가진다.

        ㆍ레코드를 저장할 때 무조건 선언한 길이 값으로 '고정'해서 저장

    - VARCHAR는 가변 길이 문자열이다.

        ㆍ길이는 0에서 65,535 사이의 값으로 지정할 수 있으며, 입력된 데이터에 따라 용량을 가변시켜 저장한다.

        ㆍ예를 들어 10글자의 이메일을 저장할 경우 10글자에 해당하는 바이트 + 길이기록용 1바이트로 저장하게된다.

        ㆍVARCHAR(10000)으로 선언했음에도 말이죠.

    - 그렇기 때문에 CHAR의 경우 유동적이지 않은 길이를 가진 데이터의 경우 효율적이며, 유동적인 길이를 가진 데이터는 VARCHAR로 저장하는 것이 좋다.

     

    TEXT와 BLOB

    - 두 개의 타입 모두 큰 데이터를 저장할 때 쓰는 타입

    - TEXT는 큰 문자열 저장에 쓰며 주로 게시판의 본문을 저장할 때 쓴다.

    - BLOB은 이미지, 동영상 등 큰 데이터 저장에 쓴다.

        ㆍ그러나 보통은 아마존의 이미지 호스팅 서비스인 S3를 이용하는 등 서버에 파일을 올리고

            파일에 관한 경로를 VARCHAR로 저장한다.

     

    ENUM과 SET

    - ENUM과 SET 모두 문자열을 열거한 타입이다.

    - ENUM은 ENUM('x-small', 'small', 'medium', 'large', 'x-large') 형태로 쓰이며, 이 중에서 하나만 선택하는 단일 선택만 가능하고 ENUM 리스트에 없는 잘못된 값을 삽입하면 빈문자열이 대신 삽입된다.

        ㆍENUM을 이용하면 x-small 등이 0,1 등으로 매핑되어 메모리를 적게 사용하는 이점을 얻는다.

        ㆍENUM은 최대 65,535개의 요소들을 넣을 수 있다.

    - SET은 ENUM과 비슷하지만 여러 개의 데이터를 선택할 수 있고 비트 단위의 연산을 할 수 있으며 최대 64개의 요소를 집어넣을 수 있다는 점이 다르다.

    - 참고로 ENUM이나  SET을 쓸 경우 공간적으로 이점을 볼 수 있지만 애플리케이션의 수정에 따라 데이터베이스의 ENUM이나 SET에서 정의한 목록을 수정해야 한다는 단점이 있다.

     

    4.1.6 관계

    - 데이터베이스에 테이블은 하나만 있는 것이 아니다.

    - 여러 개의 테이블이 있고 이러한 테이블은 서로의 관계가 정의되어 있다.

    - 이러한 관계를 관계화살표로 나타낸다 (책 p193 참고)

     

    1:1 관계

    - 예를 들어, 유저당 유저이메일은 하나이다.

    - 1:1 관계는 테이블을 두 개의 테이블로 나눠 테이블의 구조를 더 이해하기 쉽게 만들어 준다.

     

    1:N 관계

    - 예를 들어, 쇼핑몰에서 한 유저당 여러 개의 상품을 장바구니에 넣을 수 있다.

    - 이렇게 한 개체가 다른 많은 개체를 포함하는 관계를 말한다.

     

    N:M 관계

    - 예를 들어, 학생과 강의 관계 - 학생도 강의를 많이 들을 수 있고 강의도 여러 명의 학생을 포함할 수 있다.

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

     

    4.1.7 키

    - 테이블 간의 관계를 조금 더 명확하게 하고 테이블 자체의 인덱스를 위해 설정된 장치로 기본키, 외래키, 후보키, 슈퍼키, 대체키가 있다.

    - 슈퍼키는 유일성이 있고 그 안에 포함된 후보키는 최소성까지 갖춘 키이다.

    - 후보키 중에서 기본키로 선택되지 못한 키는 대체키가 된다.

    - 유일성은 중복되는 값은 없으며, 최소성은 필드를 조합하지 않고 최소 필드만 써서 키를 형성할 수 있는 것을 말한다.

     

    기본키

    - 기본키(Primary Key)는 줄여 PK 또는 프라이머리키라고 많이 부르며, 유일성과 최소성을 만족하는 키이다.

    - 이는 테이블의 데이터 중 고유하게 존재하는 속성이며, 기본키에 해당하는 데이터는 중복되서는 안된다.

    - {ID, name} 이라는 복합키를 기본키로 설정할 수 있지만 그렇게 되면 최소성을 만족하지 않는다.

    - 기본키는 자연키 또는 인조키 중에 골라 설정한다.

     

    자연키

    - 예를 들어 유저 테이블을 만든다고 가정하면 주민등록번호, 이름, 성별 등의 속성이 있다.

    - 이 중 이름, 성별 등은 중복된 값이 들어올 수 있으므로 부적절하고 남는 것은 주민등록번호이다.

    - 이런 식으로 중복된 값들을 제외하며 중복되지 않는 것을 '자연스레' 뽑다가 나오는 키를 자연키라고 한다.

    - 자연키는 언젠가 변하는 속성을 가진다.

     

    인조키

    - 예를 들어 유저 테이블을 만든다고 했을 때 회원 테이블을 생성한다고 가정하면 주민등록번호, 이름, 성별 등의 속성이 있다.

    - 여기에 인위적으로 유저 아이디를 부여한다.

    - 이를 통해 고유 식별자가 생겨난다.

    - 오라클은 sequence, MySQL은 auto increment 등으로 설정한다.

    - 이렇게 인위적으로 생성한 키를 인조키라고 한다.

    - 자연키와는 대조적으로 변하지 않는다.

    - 보통 기본키는 인조키로 설정한다.

     

    외래키

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

    - 외래키는 중복되어도 괜찮다.

     

    후보키

    - 후보키(candidate key)는 기본키가 될 수 있는 후보들이며 유일성과 최소성을 동시에 만족하는 키이다.

     

    대체키

    - 대체키(alternate key)는 후보키가 두 개 이상일 경우 어느 하나를 기본키로 지정하고 남은 후보키들을 말한다.

     

    슈퍼키

    - 슈퍼키(super key)는 각 레코드를 유일하게 식별할 수 있는 유일성을 갖춘 키이다.

     

    4.2 ERD와 정규화 과정

    - ERD(Entity Relationship Diagram) 는 데이터베이스를 구축할 때 가장 기초적인 뼈대 역할을 하며, 릴레이션 간의 관계들을 정의한 것이다.

    - 만약 서비스를 구축한다면 가장 먼저 신경 써야 할 부분이며 이 부분을 신경 쓰지 않고 서비스를 구축한다면 단단하지 않은 골조로 건무을 짓는 것이나 다름 없다.

     

    4.2.1 ERD의 중요성

    - ERD는 시스템의 요구 사항을 기반으로 작성되며 이 ERD를 기반으로 데이터베이스를 구축한다.

    - 데이터베이스를 구축한 이후에도 디버깅 또는 비즈니스 프로세스 재설계가 필요한 경우에 설계도 역할을 담당하기도 한다.

    - 하지만 ERD는 관계형 구조로 표현할 수 있는 데이터를 구성하는 데 유용할 수 있지만 비정형 데이터를 충분히 표현할 수 없다는 단점이 있다.

     

    * 비정형 데이터 : 비구조화 데이터를 말하며, 미리 정의된 데이터 모델이 없거나 미리 정의된 방식으로 정리되지 않은 정보를 말한다.

     

    4.2.3 정규화 과정

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

    - 데이터베이스 이상 현상이란 회원이 한 개의 등급을 가져야 하는데 세 개의 등급을 갖거나 삭제할 때 필요한 데이터가 같이 삭제되고, 데이터를 삽입해야 하는데 하나의 필드 값이 NULL이 되면 안되어서 삽입하기 어려운 현상을 말한다.

    - 정규화 과정은 정규형 원칙을 기반으로 정규형을 만들어가는 과정이며, 정규화된 정도는 정규형(NF, Normal Form)으로 표현한다.

    - 기본 정규형인 제1정규형, 제2정규형, 제3정규형, 보이스/코드 정규형이 있고 고급 정규형인 제4정규형, 제5정규형이 있다.

    - 이 중 기본 정규형인 제1,2,3 정규형, 보이스/코드 정규형에 대해 알아보자!

     

    정규형 원칙

    - 정규형의 원칙이란 같은 의미를 표현하는 릴레이션이지만 좀 더 좋은 구조로 만들어야 하고,

       자료의 중복성은 감소해야 하고,

       독립적인 관계는 별개의 릴레이션으로 표현해야 하며,

       각각의 릴레이션은 독립적인 표현이 가능해야하는 것을 말한다.

     

    제1정규형

    - 릴레이션의 모든 도메인이 더 이상 분해될 수 없는 원자 값(atomic value)만으로 구성되어야 한다.

    - 릴레이션의 속성 값 중에서 한 개의 기본키에 대해 두 개 이상의 값을 가지는 반복 집합이 있어서는 안된다.

    - 만약에 반복 집합이 있다면 제거해야 한다.

     

    제2정규형

    - 릴레이션이 제1정규형이며 부분 함수의 종속성을 제거한 형태를 말한다.

    - 부분 함수의 종속성 제거란 기본키가 아닌 모든 속성이 기본키에 완전 함수 종속적인 것을 말한다.

    - 이때 주의할 점은 릴레이션을 분해할 때 동등한 릴레이션으로 분해해야 하고, 정보 손실이 발생하지 않는 무손실 분해로 분해되어야 한다는 것이다.

     

    제3정규형

    - 제2정규형이고 기본키가 아닌 모든 속성이 이행적 함수 종속(transitive FD)을 만족하지 않는 상태를 말한다.

     

    이행적 함수 종속

    - 이행적 함수 종속이란 A→B와 B→C가 존재하면 논리적으로 A→C가 성립하는데, 이 때 집합 C가 집합 A에 이행적으로 함수 종속이 되었다고 한다.

     

    보이스/코드 정규형

    - 보이스/코드 정규형(BCNF)은 제3정규형이고, 결정자가 후보키가 아닌 함수 종속 관계를 제거하여 릴레이션의 함수 종속 관계에서 모든 결정자가 후보키인 상태를 말한다.

     

    * 결정자 : 함수 종속 관계에서 특정 종속자(dependent)를 결정짓는 요소, 'X→Y' 일때 X는 결정자, Y는 종속자이다.

     

    - 정규화 과정을 거쳐 테이블을 나눈다고 해서 성능이 100% 좋아지는 것은 아니다.

    - 성능이 좋아질 수도 나빠질 수도 있다.

    - 테이블을 나누게 되면 어떠한 쿼리는 조인을 해야하는 경우도 발생해서 오히려 느려질 수도 있기 때문에 서비스에 따라 정규화 또는 비정규화 과정을 진행해야 한다.

     

    4.3 트랜잭션과 무결성

    4.3.1 트랜잭션

    - 트랜잭션은 데이터베이스에서 하나의 논리적 기능을 수행하기 위한 작업의 단위를 말한다.

    - 데이터베이스에 접근하는 방법은 쿼리이므로, 즉 여러 개의 쿼리들을 하나로 묶는 단위를 말한다.

    - 이에 대한 특징은 원자성, 일관성, 독립성, 지속성이 있으며 이를 한꺼번에 ACID 특징이라고 한다.

     

    원자성

    - "all or nothing"

    - 원자성(atomicity)은 트랜잭션과 관련된 일이 모두 수행되었거나 되지 않았거나를 보장하는 특징이다.

    - 예를 들어 트랜잭션을 커밋했는데, 문제가 발생하여 롤백하는 경우 그 이후에 모두 수행되지 않음을 보장하는 것을 말한다.

    - 또한, 트랜잭션 단위로 여러 로직들을 묶을 때 외부 API를 호출하는 것이 있으면 안된다.

    - 만약 있다면 롤백이 일어났을 때 어떻게 해야 할 것인지에 대한 해결 방법이 있어야하고 트랜잭션 전파를 신경써서 관리해야 한다.

     

    커밋과 롤백

    - 커밋(commit)은 여러 쿼리가 성공적으로 처리되었다고 확정하는 명령어이다.

    - 트랜잭션 단위로 수행되며 변경된 내용이 모두 영구적으로 저장되는 것을 말한다.

    - "커밋이 수행되었다."를 "하나의 트랜잭션이 성공적으로 수행되었다."라고도 말한다.

    - 예를 들어, update, insert, delete의 쿼리가 하나의 트랜잭션 단위로 수행되고 이후에 데이터베이스에 영구 저장된다.

    - 롤백이란 트랜잭션으로 처리한 하나의 묶음 과정을 일어나기 전으로 돌리는 일(취소)을 말한다.

    - 이러한 커밋과 롤백 덕에 데이터의 무결성이 보장된다.

    - 또한, 데이터 변경 전에 변경사항을 쉽게 확인할 수 있고 해당 작업을 그룹화할 수 있다.

     

    트랜잭션 전파

    - 트랜잭션을 수행할 때 커넥션 단위로 수행하기 때문에 커넥션 객체를 넘겨서 수행해야 한다.

    - 하지만 이를 매번 넘겨주기가 어렵기도 하고 귀찮기도 하다.

    - 이를 넘겨서 수행하지 않고 여러 트랜잭션 관련 메서드의 호출을 하나의 트랜잭션에 묶이도록 하는 것을 트랜잭션 전파라고 한다.

    @Service
    @Transactional(readOnly = true)
    public class MemberService {
        private final MemberRepository memberRepository;
        
        public MemberService(MemberRepository memberRepository) {
            this.memberRepository = memberRepository;
        }
    }

    - Spring 프레임워크에서는 @Transactional 애너테이션을 통해 여러 쿼리 관련 코드들을 하나의 트랜잭션으로 처리한다.

     

    일관성

    - 일관성(consistency)은 '허용된 방식'으로만 데이터를 변경해야 하는 것을 의미한다.

    - 데이터베이스에 기록된 모든 데이터는 여러 가지 조건, 규칙에 따라 유효함을 가져야 한다.

     

    격리성

    - 격리성(isolation)은 트랜잭션 수행 시 서로 끼어들지 못하는 것을 말한다.

    - 복수의 병렬 트랜잭션은 서로 격리되어 마치 순차적으로 실행되는 것처럼 작동되어야 하고, 데이터 베이스는 여러 사용자가 같은 데이터에 접근할 수 있어야 한다.

    - 그냥 순차적으로 하면 쉽게 되겠지만 그렇게 되면 성능이 나쁘겠죠?

    - 격리성은 여러 개의 격리 수준으로 나뉘어 격리성을 보장한다.

    - 격리 수준은 SERIALIZABLE, REPEATABLE_READ, READ_COMMITTED, READ_UNCOMMITTED가 있으며 오른쪽로 갈수록 동시성이 강해지지만 격리성은 약해지고, 왼쪽으로 갈수록 동시성은 약해지고 격리성은 강해진다.

    - 예를 들어 SERIALIZABLE은 격리성이 강한데 반해, 동시성은 약하다.

    - 또한, 각 단계마다 나타나는 현상이 있다.

    - REPEATABLE_READ는 팬텀 리드,

       READ_COMMITTED는 팬텀 리드, 반복 가능하지 않은 조회가 발생하며,

       READ_UNCOMMITTED는 팬텀리드, 반복 가능하지 않은 조회, 더티 리드가 발생할 수 있다.

     

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

    - 격리 수준에 따라 발생하는 현상은 팬텀 리드, 반복 가능하지 않은 조회, 더티 리드가 있다.

     

    팬텀 리드

    - 팬텀 리드(phantom read)는 한 트랜잭션 내에서 동일한 쿼리를 보냈을 때 해당 조회 결과가 다른 경우를 말한다.

    - 예를 들어 사용자 A가 회원 테이블에서 age가 12 이상인 회원들을 조회하는 쿼리를 보낸다고 하자

        ㆍ이 결과로 세 개의 테이블이 조회한다고 해보자

        ㆍ그 다음 사용자 B가 age가 15인 회원 레코드를 삽입한다.

        ㆍ그러면 그 다음 세 개가 아닌 네 개의 테이블이 조회되는 것이다.

     

    반복 가능하지 않은 조회

    - 반복 가능하지 않은 조회(non-repeatable read)는 한 트랜잭션 내의 같은 행에 두 번 이상 조회가 발생했는데, 그 값이 다른 경우를 가르킨다.

    - 예를 들어 사용자 A가 큰돌의 보석 개수가 100개라는 값을 가진 데이터였는데,

        ㆍ그 이후 사용자 B가 그 값을 1로 변경해서 커밋했다고 하면 사용자A는 100이 아닌 1을 읽게된다.

    - 팬텀 리드와 다른 점은 반복 가능하지 않은 조회는 행 값이 달라질 수도 있는데, 팬텀 리드는 다른 행이 선택될 수도 있다는 것을 의미한다.

     

    더티 리드

    - 더티 리드(dirty read)는 반복 가능하지 않은 조회와 유사하며 한 트랜잭션이 실행 중일 때 다른 트랜잭션에 의해 수정되었지만 아직 '커밋되지 않은' 행의 데이터를 읽을 수 있을 때 발생한다.

    - 예를 들어 사용자 A가 큰돌의 보석 개수 100을 1로 변경한 내용이 '커밋되지 않은' 상태라도 그 이후 사용자 B가 조회한 결과가 1로 나오는 경우를 말한다.

     

    격리 수준

    SERIALIZABLE

    - SERIALIZABLE은 말 그대로 트랜잭션을 순차적으로 진행시키는 것을 말한다.

    - 여러 트랜잭션이 동시에 같은 행에 접근할 수 없다.

    - 이 수준은 매우 엄격한 수준으로 해당 행에 대해 격리시키고, 이후 트랜잭션이 이 행에 대해 일어난다면 기다려야 한다.

    - 그렇기 때문에 교착 상태가 일어날 확률도 많고 가장 성능이 떨어지는 격리 수준이다.

     

    REPEATABLE_READ

    - REPEATABLE_READ 는 하나의 트랜잭션이 수정한 행을 다른 트랜잭션이 수정할 수 없도록 막아주지만 새로운 행을 추가하는 것은 막지 않는다.

    - 따라서 이후에 추가된 행이 발견될 수 도 있습니다.

     

    READ_COMMITTED

    - READ_COMMITTED는 가장 많이 사용되는 격리 수준이며 MySQL8.0, PostgreSQL, SQL Server, 오라클에서 기본값으로 설정되어 있다.

    - READ_UNCOMMITTED와는 달리 다른 트랜잭션이 커밋하지 않은 정보는 읽을 수 없다.

    - 즉, 커밋 완료된 데이터에 대해서만 조회를 허용한다.

    - 하지만 어떤 트랜잭션이 접근한 행을 다른 트랜잭션이 수정할 수 있다.

    - 예를 들어 트랜잭션 A가 수정한 행을 트랜잭션 B가 수정할 수도 있다.

        ㆍ이 때문에 트랜잭션 A가 같은 행을 다시 읽을 때 다른 내용이 발견될 수 있다.

     

    READ_UNCOMMITTED

    - READ_UNCOMMITTED는 가장 낮은 격리 수준으로, 하나의 트랜잭션이 커밋되기 이전에 다른 트랜잭션에 노출되는 문제가 있지만 가장 빠르다.

    - 이는 데이터 무결성을 위해 되도록이면 사용하지 않는 것이 이상적이나, 몇몇 행이 제대로 조회되지 않더라도 괜찮은 거대한 양의 데이터를 '어림잡아' 집계하는 데는 사용하면 좋다.

     

    지속성

    - 지속성(durability)은 성공적으로 수행된 트랜잭션은 영원히 반영되어야 하는 것을 의미한다.

    - 이는 데이터베이스에 시스템 장애가 발생해도 원래 상태로 복수하는 회복 기능이 있어야 함을 뜻하며, 데이터 베이스는 이를 위해 체크섬, 저널링, 롤백 등의 기능을 제공한다.

     

    * 체크섬 : 중복 검사의 한 형태로, 오류 정정을 통해 송신된 자료의 무결성을 보호하는 단순한 방법

    * 저널링 : 파일 시스템 또는 데이터베이스 시스템에 변경 사항을 반영(commit)하기 전에 로깅하는 것

    - 트랜잭션 등 변경 사항에 대한 로그를 남기는 것

     

    4.3.2 무결성

    - 무결성이란 데이터의 정확성, 일관성, 유효성을 유지하는 것을 말하며, 무결성이 유지되어야 데이터베이스에 저장된 데이터 값과 그 값에 해당하는 현실 세계의 실제 값이 일치하는지에 대한 신뢰가 생긴다.

    - 무결성의 종류

    이름 설명
    개체 무결성 기본키로 선택된 필드는 빈 값을 허용하지 않는다.
    참조 무결성 서로 참조 관계에 있는 두 테이블의 데이터는 항상 일관된 값을 유지해야 한다.
    고유 무결성 특정 속성에 대해 고유한 값을 가지도록 조건이 주어진 경우 그 속성 값은 모두 고유한 값을 가진다.
    NULL 무결성 특정 속성 값에 NULL이 올 수 없다는 조건이 주어진 경우 그 속성 값은 NULL이 될 수 없다는 제약 조건이다.

     

    4.4 데이터베이스의 종류

    4.4.1 관계형 데이터베이스

    - 관계형 데이터베이스(RDBMS)는 행과 열을 가지는 표 형식 데이터를 저장하는 형태의 데이터베이스를 가리키며 SQL이라는 언어를 써서 조작한다.

    - MySQL, PostgreSQL, 오라클, SQL Server, MSSQL 등이 있다.

    - 참고로 관계형 데이터베이스의 경우 표준 SQL은 지키기는 하지만, 각각의 제품에 특화시킨 SQL을 사용한다.

    - 예를 들어 오라클의 경우 PL/SQL이라고 하며, SQL Server에서는 T-SQL, MySQL은 SQL을 쓴다.

     

    MySQL

    - MySQL은 대부분의 운영체제와 호환되며 현재 가장 많이 사용하는 데이터베이스이다.

    - 스택 오버플로우에서 조사한 결과(2021)에서 MySQL은 아직도 압도적으로 가장 많이 쓰는 데이터베이스이며 메타, 트위터 등 많은 기업에서 MySQL을 사용하고 있다.

    - C, C++로 만들어졌으며 MyISAM 인덱스 압축 기술, B-트리 기반의 인덱스, 스레드 기반의 메모리 할당 시스템, 매우 빠른 조인, 최대 64개의 인덱스를 제공한다.

    - 대용량 데이터베이스를 위해 설계되어 있고 롤백, 커밋, 이중 암호 지원 보안 등의 기능을 제공하며 많은 서비스에서 사용한다.

    - MySQL의 스토리 엔진 아키텍처는 p214 참조

    - 데이터베이스의 심장과도 같은 역할을 하는 곳이 바로 스토리지 엔진인데, 모듈식 아키텍처로 쉽게 스토리지 엔진을 바꿀 수 있으며 데이터 웨어하우징, 트랜잭션 처리, 고가용성 처리에 강점을 두고 있다.

    - 스토리지 엔진 위에는 커넥터 API 및 서비스 계층을 통해 MySQL 데이터베이스와 쉽게 상호 작용할 수 있다.

    - 또한, MySQL은 쿼리 캐시를 지원해서 입력된 쿼리 문에 대한 전체 결과 집합을 저장하기 때문에 사용자가 작성한 쿼리가 캐시에 있는 쿼리와 동일하면 서버는 단순히 구문 분석, 최적화 및 실행을 건너뛰고 캐시의 출력만 표시한다.

     

    PostgreSQL

    - PostgreSQL은 MySQL 다음으로 개발자들이 선호하는 데이터베이스 기술로 널리 인정받고 있다.

    - 디스크 조각이 차지하는 영역을 회수할 수 있는 장치인 VACUUM의 특징이다.

    - 최대 테이블의 크기는 32TB이며 SQL뿐만 아니라 JSON을 이용해서 데이터에 접근할 수 있다.

    - 지정 시간에 복구하는 기능, 로깅, 접근 제어, 중첩된 트랜잭션, 백업 등을 할 수 있다.

     

    4.4.2 NoSQL 데이터베이스

    - NoSQL(Not only SQL)이라는 슬로건에서 생겨난 데이터베이스이다.

    - SQL을 사용하지 않는 데이터베이스를 말하며, 대표적으로 MongoDB와 redis 등이 있다.

     

    MongoDB

    - MongoDB는 JSON을 통해 데이터에 접근할 수 있고, Binary JSON 형태(BSON)로 데이터가 저장되며 와이어드타이거 엔진이 기본 스토리지 엔진으로 장착된 키-값 데이터 모델에서 확장된 도큐먼트 기반의 데이터베이스이다

    - 확장성이 뛰어나며 빅데이터를 저장할 때 성능이 좋고 고가용성과 샤딩, 레플리카셋을 지원한다.

    - 또한, 스키마를 정해 놓지 않고 데이터를 삽입할 수 있기 때문에 다양한 도메인의 데이터베이스를 기반으로 분석하거나 로깅 등을 구현할 때 강점을 보인다.

    - 또한, MongoDB는 도큐먼트를 생성할 때마다 다른 컬렉션에서 중복된 값을 지니기 힘든 유니크한 값인 ObjectID가 생성된다.

    - 이는 기본키로 유닉스 시간 기반의 타임스탬프(4바이트), 랜덤 값(5바이트), 카운터(3바이트)로 이루어져 있다.

     

    redis

    - redis는 인메모리 데이터베이스이자 키-값 데이터 모델 기반의 데이터베이스이다.

    - 기본적으로 데이터 타입은 문자열(string)이며 최대 512MB까지 저장할 수 있다.

    - 이외에 셋(set), 해시(hash) 등을 지원한다.

    - pub/sub 기능을 통해 채팅 시스템, 다른 데이터베이스 앞단에 두어 사용하는 캐싱 계층, 단순한 키-값이 필요한 세션 정보 관리, 정렬된 셋(sorted set) 자료 구조를 이용한 실시간 순위표 서비스에 사용한다.

     

    4.5 인덱스

    4.5.1 인덱스의 필요성

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

    - 예를 들어 책의 마지막 장에 있는 찾아보기를 생각하면 된다.

        ㆍ책의 본문이 있고 그 본문 안에 내가 찾고자 하는 '항목'을 찾아보기를 통해 빠르게 찾을 수 있다.

    - 이와 마찬가지로 인덱스를 설정하면 테이블 안에 내가 찾고자 하는 데이터를 빠르게 찾을 수 있다.

     

    4.5.2 B-트리

    - 인덱스는 보통 B-트리라는 자료 구조로 이루어져 있다.

    - 이는 루트 노드, 리프 노트, 그리고 루트 노드와 리프 노드 사이에 있는 브랜치 노드로 나뉜다.

    - 먼저 루트 노드와 리프 노드를 기반으로 설명하면 다음과 같다.

    - 예를 들어 E를 찾는다고 하면 전체 테이블을 탐색하는 것이 아니라 E가 있을 법한 리프 노드로 들어가서 E를 탐색하면 쉽게 찾을 수 있다.

    - 이 자료 구조 없이 E를 탐색하고자 하면 A,B,C,D,E 다섯 번을 탐색해야 하지만, 이렇게 노드들로 나누면 두번만에 리프 노드에서 찾을 수 있다.

    - 좀 더 자세한 예

        ㆍ키 57에 해당하는 데이터를 검색해야 한다고 보자.

        ㆍ트리 탐색은 맨 위 루트 노드부터 탐색이 일어나며 브랜치 노드를 거쳐 리프 노드까지 내려온다.

        ㆍ'57보다 같거나 클 때까지 <='를 기반으로 처음 루트 노드에서는 39, 83 이후 아래 노드로 내려와 46, 53, 57 등

            정렬된 값을 기반으로 탐색하는 것을 볼 수 있다.

        ㆍ이렇게 루트 노드부터 시작하여 마지막 리프 노드에 도달해서 57이 가리키는 데이터 포인터를 통해 결괏값을 반환하게 된다.

     

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

    - 인덱스가 효율적인 이유는 효율적인 단계를 거쳐 모든 요소에 접근할 수 있는 균형 잡힌 트리 구조와 트리 깊이의 대수 확장성 때문이다.

    - 대수확장성이란 트리 깊이가 리프 노드 수에 비해 매우 느리게 성장하는 것을 의미한다.

    - 기본적으로 인덱스가 한 깊이씩 증가할 때마다 최대 인덱스 항목의 수는 4배씩 증가한다.

    트리 깊이 인덱스 항목의 수
    3 64
    4 256
    5 1024
    6 4096
    7 16384
    8 65536
    9 262144
    10 1048576

    - 앞의 표처럼 트리 깊이는 열 개짜리로, 100만 개의 레코드를 검색할 수 있다는 의미이다.

    - 참고로 실제 인덱스는 이것보다 훨씬 더 효율적이며, 그렇기 때문에 인덱스가 효율적이라고 할 수 있다.

     

    4.5.3 인덱스 만드는 방법

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

     

    MySQL

    - MySQL의 경우 클러스터형 인덱스와 세컨더리 인덱스가 있으며, 클러스터형 인덱스는 테이블당 하나를 설정할 수 있다.

    - primary key 옵션으로 기본키로 만들면 클러스터형 인덱스를 생성할 수 있고, 기본키로 만들지 않고 unique not null 옵션을 붙이면 클러스터형 인덱스로 만들 수 있다.

    - create index... 명령어를 기반으로 만들면 세컨더리 인덱스를 만들 수 있다.

    - 하나의 인덱스만 생성할 것이라면 클러스터형 인덱스를 만드는 것이 세컨더리 인덱스를 만드는 것보다 성능이 좋다.

    - 세컨더리 인덱스는 보조 인덱스로 여러 개의 필드 값을 기반으로 쿼리를 많이 보낼 때 생성해야 하는 인덱스이다.

    - 예를 들어 age라는 하나의 필드만으로 쿼리를 보낸다면 클러스터형 인덱스만 필요하겠죠?

        ㆍ하지만 age, name, email 등 다양한 필드를 기반으로 쿼를 보낼 때는 세컨더리 인덱스를 사용해야 한다.

     

    MongoDB

    - MongoDB의 경우 도큐먼트를 만들면 자동으로 ObjectID가 형성되며, 해당 키가 기본키로 설정된다.

    - 그리고 세컨더리키도 부가적으로 설정해서 기본키와 세컨더리키를 같이 쓰는 복합 인덱스를 설정할 수 있다.

     

    4.5.4 인덱스 최적화 기법

    - 인덱스 최적화 기법은 데이터베이스마다 조금씩 다르지만 기본적인 골조는 똑같기 때문에 특정 데이터베이스를 기준으로 설명해도 무방하다.

    - 이 책에서 MongoDB를 기반으로 인덱스 최적화 기법을 설명하며, 이를 기반으로 다른 데이터베이스에 웬만큼 적용할 수 있다.

     

    1. 인덱스는 비용이다

    - 먼저 인덱스는 두 번 탐색하도록 강요한다.

    - 인덱스 리스트, 그다음 컬렉션 순으로 탐색하기 때문이며, 관련 읽기 비용이 들게 된다.

    - 또한, 컬렉션이 수정되었을 때 인덱스도 수정되어야 한다.

    - 마치 책의 본문이 수정되었을 때 목차나 찾아보기도 수정해야 하듯이 말이죠

    - 이때 B-트리의 높이를 균형 있게 조절하는 비용도 들고, 데이터를 효율적으로 조회할 수 있도록 분산시키는 비용도 들게 된다.

    - 그렇기 때문에 쿼리에 있는 필드에 인덱스를 무작정 다 설정하는 것은 답이 아니다.

    - 또한, 컬렉션에서 가져와야 하는 양이 많을수록 인덱스를 사용하는 것은 비효율적이다.

     

    2. 항상 테스팅하라

    - 인덱스 최적화 기법은 서비스 특징에 따라 달라진다.

    - 서비스에서 사용하는 객체의 깊이, 테이블의 양 등이 다르기 때문이다.

    - 그렇기 때문에 항상 테스팅하는 것이 중요하다

    - explain() 함수를 통해 인덱스를 만들고 쿼리를 보낸 이후에 테스팅을 하며 걸리는 시간을 최소화해야 한다.

    - 참고로 MySQL에서는 다음과 같은 코드로 테스팅을 수행한다.

    EXPLAIN
    SELECT * FROM t1
    JOIN t2 ON t1.c1 = t2.c1

     

    3. 복합 인덱스는 같음, 정렬, 다중 값, 카디널리티 순이다.

    - 보통 여러 필드를 기반으로 조회할 때 복합 인덱스를 생성하는데, 이 인덱스를 생성할 때는 순서가 있고 생성 순서에 따라 인덱스 성능이 달라진다.

    - 같음, 정렬, 다중 값, 카디널리티 순으로 생성해야 한다.

    1. 어떠한 값과 같음을 비교하는 == 이나 equal 이라는 쿼리가 있다면 제일 먼저 인덱스로 설정한다.

    2. 정렬에 쓰는 필드라면 그다음 인덱스로 설정한다.

    3. 다중 값을 출력해야 하는 필드, 즉 쿼리 자체가 >이거나 < 등 많은 값을 출력해야 하는 쿼리에 쓰는 필드라면 나중에 인덱스를 설정한다.

    4. 유니크한 값의 정도를 카디널리티라고 한다.

        ㆍ이 카디널리티가 높은 순서를 기반으로 인덱스를 생성해야 한다.

        ㆍ예를 들어 age와 email이 있다고 해보자

        ㆍ어떤 것이 더 높죠? 당연히 email이다.

        ㆍ즉, email이라는 필드에 대한 인덱스를 먼저 생성해야 하는 것이다.

     

    4.6 조인의 종류

    - 조인(join)이란 하나의 테이블이 아닌 두 개 이상의 테이블을 묶어서 하나의 결과물을 만드는 것을 말한다.

    - MySQL에서는 JOIN이라는 쿼리로, MongoDB에서는 lookup이라는 쿼리로 이를 처리할 수 있다.

    - 참고로 MongoDB를 사용할 때 lookup은 되도록 사용하지 말아야 한다.

    - MongoDB는 조인 연산(lookup)에 대해 관계형 데이터베이스보다 성능이 떨어진다고 여러 벤치마크 테스트에서 알려져 있다.

    - 따라서 여러 테이블을 조인하는 작업이 많을 경우 MongoDB보다는 관계형 데이터베이스를 써야한다.

    - 조인의 종류 중 대표적인 내부 조인, 왼쪽 조인, 오른쪽 조인, 합집합 조인을 살펴보자

    ㆍ내부조인(inner join) : 왼쪽 테이블과 오른쪽 테이블의 두 행이 모두 일치하는 행이 있는 부분만 표기한다.

    ㆍ왼쪽조인(left outer join) : 왼쪽 테이블의 모든 행이 결과 테이블에 표기된다.

    ㆍ오른쪽조인(right outer join) : 오른쪽 테이블의 모든 행이 결과 테이블에 표기된다.

    ㆍ합집합조인(full outer join) : 두 개의 테이블을 기반으로 조인 조건에 만족하지 않는 행까지 모두 표기한다.

    - SQL의 JOIN을 시각화해서 볼 수 있는 사이트 : https://sql-joins.leopard.in.ua/ 

     

    SQL Joins Visualizer

    Please select how do you want to do SQL JOIN between two table Copy SQL

    sql-joins.leopard.in.ua

    - 앞으로 설명할 때 왼쪽 테이블은 A, 오른쪽 테이블은 B라 하고 설명하겠다.

     

    4.6.1  내부 조인

    - 내부 조인은 두 테이블 간에 교집합을 나타낸다.

    SELECT * FROM TableA A
    INNER JOIN TableB B ON
    A.key = B.key

     

    4.6.2 왼쪽 조인

    - 왼쪽 조인은 테이블 B의 일치하는 부분의 레코드와 함께 테이블 A를 기준으로 완전한 레코드 집합을 생성한다.

    - 만약 테이블 B에 일치하는 항목이 없으면 해당 값은 null 값이 된다.

    SELECT * FROM TableA A
    LEFT JOIN TableB B ON
    A.key = B.key

     

    4.6.3 오른쪽 조인

    - 오른쪽 조인은 테이블 A에서 일치하는 부분의 레코드와 함께 테이블 B를 기준으로 완전한 레코드 집합을 생성한다.

    - 만약 테이블 A에 일치하는 항목이 없으면 해당 값은 null값이 된다.

    SELECT * FROM TableA A
    RIGHT JOIN TABLEB B ON
    A.key = B.key

     

    4.6.4 합집합 조인

    - 합집합 조인(완전 외부 조인)은 양쪽 테이블에서 일치하는 레코드와 함께 테이블 A와 테이블 B의 모든 레코드 집합을 생성한다.

    - 이때 일치하는 항목이 없으면 누락된 쪽에 null 값이 포함되어 출력된다.

    SELECT * FROM TableA A
    FULL OUTER JOIN TableB B ON
    A.key = B.key

     

    4.7 조인의 원리

    - 앞서 설명한 조인은 조인의 원리를 기반으로 조인 작업이 이루어진다.

    - 조인의 원리인 중첩 루프 조인, 정렬 병합 조인, 해시 조인에 대해 알아보자!

    - 앞서 설명한 조인의 종류는 이 원리를 기반으로 조인을 하는 것이다.

     

    4.7.1 중첩 루프 조인

    - 중첩 루프 조인(NLJ, Nested Loop Join)은 중첩 for 문과 같은 원리로 조건에 맞는 조인을 하는 방법이며, 랜덤 접근에 대한 비용이 많이 증가하므로 대용량의 테이블에서는 사용하지 않는다.
    - 예를 들어 "t1, t2 테이블을 조인한다." 라고 했을 때 첫 번째 테이블에서 행을 한 번에 하나씩 읽고 그다음 테이블에서도 행을 하나씩 읽어 조건에 맞는 레코드를 찾아 결괏값을 반환한다.

    for each row in t1 matching reference key {
        for each row in t2 matching reference key {
            if row satisfies join conditions, send to client
        }
    }

    - 참고로 중첩 루프 조인에서 발전한 조인할 테이블을 작은 블록으로 나눠서 블록 하나씩 조인하는 블록 중첩 루프 조인(BNL, Block Nested Loop)이라는 방식도 있다.

     

    4.7.2 정렬 병합 조인

    - 정렬 병합 조인이란 각각의 테이블을 조인할 필드 기준으로 정렬하고 정렬이 끝난 이후에 조인 작업을 수행하는 조인이다.

    - 조인할 때 쓸 적절한 인덱스가 없고 대용량의 테이블들을 조인하고 조인 조건으로 <,> 등 범위 비교 연산자가 있을 때 쓴다.

     

    4.7.3 해시 조인

    - 해시 조인은 해시 테이블을 기반으로 조인하는 방법이다.

    - 두 개의 테이블을 조인한다고 했을 때 하나의 테이블이 메모리에 온전히 들어간다면 보통 중첩 루프 조인보다 더 효율적이다.

       (메모리에 올릴 수 없을 정도로 크다면 디스크를 사용하는 비용이 발생된다.)

    - 또한, 동등(=) 조인에서만 사용할 수 있다.

    - MySQL의 경우 MySQL8.0.18 릴리스와 함께 이 기능을 사용할 수 있게 되었으며 이를 기반으로 해시 조인의 과정을 살펴보자!

    - MySQL의 해시 조인 단계는 빌드 단계, 프로브 단계로 나뉜다.

     

    빌드 단계

    - 빌드 단계는 입력 테이블 중 하나를 기반으로 메모리 내 해시 테이블을 빌드하는 단계이다.

    - 예를 들어 persons와 countires라는 테이블을 조인한다고 했을 때 둘 중에 바이트가 더 작은 테이블을 기반으로 해서 테이블을 빌드한다.

    - 또한, 조인에 사용되는 필드가 해시 테이블의 키로 사용된다.

    - 'countries.country_id' 가 키로 사용되는 것을 볼 수 있다.

     

    프로브 단계

    - 프로브 단계 동안 레코드 읽기를 시작하며, 각 레코드에서 'persons.country_id'에 일치하는 레코드를 찾아서 결괏값으로 반환한다.

    - 이를 통해 각 테이블은 한 번씩만 읽게 되어 중첩해서 두 개의 테이블을 읽는 중첩 루프 조인보다 보통은 성능이 더 좋다.

    - 참고로 사용 가능한 메모리양은 시스템 변수 join_buffer_size에 의해 제어되며, 런타임 시에 조정할 수 있다.


    예상질문

    Q. 데이터베이스는 무엇인가?

    A. 데이터베이스(DB, DataBase)는 일정한 규칙, 혹은 규약을 통해 구조화되어 저장되는 데이터의 모음이다.

    - 해당 데이터베이스를 제어, 관리하는 통합 시스템을 DBMS(DataBase Management System)라고 하며, 데이터베이스안에 있는 데이터들은 특정 DBMS마다 정의된 쿼리 언어(query language)를 통해 삽입, 삭제, 수정, 조회 등을 수행할 수 있다.

    - 또한, 데이터베이스는 실시간 접근과 동시 공유가 가능하다.

     

    Q. 중첩 루프 조인이 무엇인가?

    A. 중첩 루프 조인(NLJ, Nested Loop Join)은 중첩 for 문과 같은 원리로 조건에 맞는 조인을 하는 방법이며, 랜덤 접근에 대한 비용이 많이 증가하므로 대용량의 테이블에서는 사용하지 않는다.

    - 예를 들어 "t1, t2 테이블을 조인한다." 라고 했을 때 첫 번째 테이블에서 행을 한 번에 하나씩 읽고 그다음 테이블에서도 행을 하나씩 읽어 조건에 맞는 레코드를 찾아 결괏값을 반환한다.

     

    Q. 인덱스를 매 필드마다 설정하는 것이 좋을까?

    A. 먼저 인덱스는 두 번 탐색을 강요한다.

    - 인덱스 리스트, 그 다음 컬렉션 이렇게 두 번을 탐색하기 때문이며 읽기 관련 비용이 더 들게 된다.

    - 그렇기 때문에 매 필드마다 설정하는 것을 고찰해봐야한다.

    - 또한, 테이블이 수정되면 인덱스도 수정되어야 한다.

    - 책의 본문이 수정되면 목차나 찾아보기도 수정해야 하듯이 말이죠

    - 그리고 인덱스를 수정하는 것은 a=1을 a=2처럼 값만 수정하는 것보다 쉽지 않다.

    - B-트리 구조를 사용하기 때문에 트리의 높이를 균형 있게 조절하는 비용도 들고 데이터를 분산시켜서 효율적으로 조회할 수 있도록 구축하는 비용도 든다.

    - 그렇기 때문에 필드에 인덱스를 무작정 다 설정하는 것은 답이 아니다.

    - 또한, 컬렉션에서 가져와야 하는 양이 많을수록 인덱스를 사용하는 것은 비효율적이다.

     

     

     

     

     

    'Books > 면접을 위한 CS 전공지식 노트' 카테고리의 다른 글

    5장 자료구조  (0) 2023.02.03
    3장 운영체제  (0) 2023.01.31
    2장 네트워크  (0) 2023.01.25
    1장 디자인 패턴과 프로그래밍 패러다임  (0) 2022.12.31

    댓글

Designed by Tistory.