본문 바로가기

클라우드(Cloud)

[스나이퍼팩토리] 카카오클라우드 AIaaS 마스터 클래스 4주차 - DB2 (데이터베이스2 - JOIN/인덱스/백업)

https://dsin.wordpress.com/wp-content/uploads/2013/03/sqljoins_cheatsheet.png

📌 JOIN 

1️⃣ JOIN이란?

JOIN은 두 개 이상의 테이블을 공통된 컬럼(주로 외래키/기본키)을 기준으로 결합해서 하나의 결과 집합을 만드는 SQL 연산이다. 

➡️ 왜 JOIN이 필요한가?

정규화를 거치면 데이터가 여러 테이블에 나눠지기 때문에,
필요한 정보를 얻기 위해 관련 테이블들을 조합해서 하나의 결과로 보는 것이 필수적이다. 


2️⃣ JOIN의 기본 구문

SELECT 컬럼명 
FROM 테이블1 
JOIN 테이블2 
ON 테이블1.컬럼 = 테이블2.컬럼
;

 

 보통 기본키(PK)외래키(FK)를 연결하는 경우가 다수이다. 


3️⃣ JOIN의 종류 정리

JOIN 종류 설명 결과
INNER JOIN 양쪽 테이블에 모두 존재하는 경우만 교집합
LEFT JOIN 왼쪽 테이블은 모두, 오른쪽은 일치하는 값만 왼쪽 기준 전체
RIGHT JOIN 오른쪽 테이블은 모두, 왼쪽은 일치하는 값만 오른쪽 기준 전체
FULL OUTER JOIN 양쪽 모두 포함 (일치하지 않아도 포함) 합집합
CROSS JOIN 조인 조건 없이 모든 조합 곱집합

✅ MySQL에서는 FULL OUTER JOIN을 UNION으로 우회 구현해야 한다. 

 


JOIN은 말로만 들으면 헷갈리고 이해하기 쉽지 않기에 예시를 통해 이해하는 것이 좋다. 

아래에 customer 테이블order 테이블이 예시로 나와있다. 아래 예시를 통해 JOIN을 이해해 보자. 

4️⃣ 예시 테이블

📋 customers 테이블

customer_id name
1 서연
2 민수
3 지우

📋 orders 테이블

order_id customer_id product
101 1 노트북
102 2 키보드
103 4 마우스

5️⃣ JOIN 실습 예제

✅ INNER JOIN (공통된 데이터만) 

SELECT c.name, o.product 
FROM customers c 
INNER JOIN orders o -- INNER JOIN과 JOIN은 같은 것을 의미하는 명령어이다. 
ON c.customer_id = o.customer_id
;

 

📌 결과:

name product
서연 노트북
민수 키보드
※ customer_id = 4는 customers에 없기 때문에 제외. 

 

기본적인 JOIN 즉, INNER JOIN은 두 테이블의 데이터 중에 공통된 데이터만을 추출해 결과로 출력한다. 

customer 테이블orders 테이블customer_id를 기준으로 JOIN을 수행하면 위와 같은 결과가 출력되는 것을 볼 수 있다. 


✅ LEFT JOIN (왼쪽 테이블 전부 + 매칭되는 오른쪽)

SELECT c.name, o.product 
FROM customers c 
LEFT JOIN orders o 
ON c.customer_id = o.customer_id
;

 

📌 결과:

name product
서연 노트북
민수 키보드
지우 NULL
※ '지우'는 주문이 없지만, LEFT JOIN이라 출력.

 

LEFT JOIN은 왼쪽의 테이블을 기준으로 한다. 

 

왼쪽의 테이블에 해당하는 데이터는 모두 출력하며, 그에 매칭되는 오른쪽 테이블의 데이터를 도출하여 출력한다. 

왼쪽 테이블에 해당하는 customer 테이블은 모든 데이터가 출력되지만, 오른쪽 테이블에 해당하는 orders 테이블은 customer_id를

기준으로 매칭되는 서연과 민수의 데이터만 포함되며 지우는 NULL 값을 가지며 출력되게 된다.  


✅ RIGHT JOIN (오른쪽 테이블 전부 + 매칭되는 왼쪽)

SELECT c.name, o.product 
FROM customers c 
RIGHT JOIN orders o 
ON c.customer_id = o.customer_id
;

 

📌 결과:

name product
서연 노트북
민수 키보드
NULL 마우스

RIGHT JOIN은 오른쪽 테이블을 기준으로 한다. 

LEFT JOIN과는 반대로 오른쪽 테이블의 데이터는 모두 출력하며, 왼쪽 테이블의 데이터는 매칭되는 데이터만 출력한다. 


✅ FULL OUTER JOIN (MySQL은 UNION으로 실행)

-- MySQL에서 FULL OUTER JOIN 대신 
SELECT c.name, o.product 
FROM customers c 
LEFT JOIN orders o 
ON c.customer_id = o.customer_id 

UNION 

SELECT c.name, o.product 
FROM customers c 
RIGHT JOIN orders o 
ON c.customer_id = o.customer_id
;

 

📌 결과:

name product
서연 노트북
민수 키보드
지우 NULL
NULL 마우스

결과와 같이 FULL OUTER JOIN은 두 테이블의 데이터를 모두 포함하여, 어느 한쪽에만 존재하는 데이터까지 모두 출력한다. 


하지만 MySQL에서는 이를 직접 지원하지 않기 때문에 LEFT JOIN과 RIGHT JOIN을 UNION으로 합쳐 구현해야 한다. 
따라서 결과에는 한쪽에만 존재하는 행도 포함되며, 존재하지 않는 컬럼은 NULL로 출력된다. 


✅ CROSS JOIN

SELECT c.name, o.product 
FROM customers c 
CROSS JOIN orders o
;

 

📌 결과: 고객 3명 × 주문 3개 = 9개의 모든 조합

 

CROSS JOIN은 조인 조건 없이 두 테이블의 모든 행을 조합하여 출력하는 방식이다. 


한 테이블의 각 행이 다른 테이블의 모든 행과 결합되므로, 총 결과는 왼쪽 테이블 행 수 × 오른쪽 테이블 행 수가 된다. 
따라서 데이터 양이 많을수록 결과가 기하급수적으로 증가하므로 주의해서 사용해야 한다. 


6️⃣ JOIN vs 서브쿼리

항목 JOIN 서브쿼리
성능 JOIN이 빠른 경우 많음 (인덱스 활용) 느릴 수 있음
가독성 테이블 관계가 명확하게 표현됨 복잡한 로직 표현에는 유리
사용 목적 여러 테이블의 수평 결합 계산값 등 수직 결합

서브쿼리는 하나의 SQL 쿼리문 내에서 다른 SELECT 문을 중첩해서 사용하는 것을 의미한다. 즉, "쿼리 안의 쿼리"라고 할 수 있다. 

 

보통 아래와 같이 메인 쿼리(Main Query) 안에 소괄호 ()로 감싸서 사용하고, 그 결과값을 조건으로 사용하거나, 결과 집합에 포함시킨다. 

-- use SubQuery
SELECT title
FROM film
WHERE film_id IN (
	SELECT film_id 
    FROM film_category fc
    JOIN category ON fc.category_id = category.category_id
    WHERE category.name = 'Action'
);

 

서브쿼리와 JOIN을 공부하다가 의문이 든 점이 있다. 

서브쿼리로 표현하는 것과 JOIN으로 표현하는 것의 결과는 똑같은 결과가 출력될 수 있는데 왜 굳이 서브쿼리를 만들어서 사용하는가?

 

사실 서브쿼리를 이용한 쿼리문은 모두 JOIN으로 표현이 가능하다. 하지만 왜 우리는 서브쿼리라는 방법을 고안했는가를 생각해 보면 JOIN을 사용한 쿼리문이 더 빠른 성능을 보이기도 하지만 직관적으로 보는 가독성 높은 쿼리문을 작성해야 할 때, 서브쿼리를 사용한다. 

 

서브쿼리는 JOIN을 사용한 쿼리문보다 눈으로 보기에 직관적으로 무엇을 출력하고자 하는지를 이해할 수 있다.

이런 장점으로 인해 서브쿼리를 작성해서 사용한다고 생각하면 된다. 


🧑‍💻 JOIN의 적용 예시 

상황 JOIN
정규화된 여러 테이블에서 데이터를 하나로 묶을 때 INNER JOIN / LEFT JOIN
사용자 목록 + 최근 활동 포함하려면 LEFT JOIN + ORDER BY
전체 목록을 빠르게 출력 INNER JOIN + 인덱스
전체 데이터 상태 확인 FULL OUTER JOIN (UNION 사용)

 

이제는 RDB를 사용할 때 가장 중요한 점 중 하나라고 할 수 있는 인덱스(Index)에 대해 알아볼 것이다. 

인덱스(Index)를 사용해서 DB를 관리해야 그의 성능을 최적화할 수 있다. 

📌 인덱스(Index)

1️⃣ 인덱스란?

인덱스(Index)는 테이블에서 원하는 데이터를 빠르게 찾기 위한 자료구조로, 쉽게 말해, 책의 "목차" 같은 역할을 한다. 

🧠 예시:

수천 페이지의 책에서 "쿠버네티스" 내용을 찾으려면 목차(Index)를 보는 게 빠를 것이다. 


2️⃣ 인덱스의 역할

역할 설명
검색 속도 향상 원하는 데이터를 빠르게 찾을 수 있음 (전체 스캔 방지)
WHERE 조건 최적화 조건절에서 인덱스 사용 시 쿼리 성능 향상
JOIN 최적화 조인할 때 키 컬럼에 인덱스가 있으면 성능 향상
ORDER BY 최적화 정렬할 컬럼에 인덱스가 있으면 정렬 속도 향상
UNIQUE 제약조건 지원 중복 방지를 위해 인덱스를 활용함

3️⃣ 인덱스의 단점

단점 설명
쓰기 성능 저하 INSERT/UPDATE/DELETE 시 인덱스도 같이 갱신돼야 함
디스크 사용 증가 인덱스 자체도 저장공간을 차지함
과도한 인덱스는 독 너무 많으면 오히려 성능 저하 초래 가능

4️⃣ 인덱스의 종류

인덱스(Index) 설명 사용 사례
B-tree 인덱스 가장 일반적인 인덱스, 균형 이진 트리 기반 범위 검색, 일반 검색
해시 인덱스 해시 함수 기반, 동등 비교에만 최적 = 검색
비트맵 인덱스 0/1로 상태 저장, 데이터 값이 적을 때 효율적 성별, 요일 등
Full-text 인덱스 텍스트 검색용 (자연어 검색) 블로그, 문서
Spatial 인덱스 공간 데이터 검색 (GIS 등) 위치 기반 서비스

5️⃣ B-Tree 인덱스란? 

✅ 정의

B-Tree(Balanced Tree) 인덱스는 균형 이진트리를 기반으로 한 인덱스로, 대부분의 RDBMS(MySQL, PostgreSQL 등)에서 기본 인덱스로 사용된다. 


🌳 구조 설명

  • 균형 트리 구조: 루트 → 중간 노드 → 리프 노드
  • 리프 노드에는 실제 데이터 위치(Pointer) 정보가 저장됨
  • 모든 리프 노드의 깊이가 동일해서 탐색 속도가 균일함
        [50] 
        / \ 
    [20]    [70] 
    / \      / \ 
  [10][30] [60][80]

👉 값을 찾을 때 이진 탐색처럼 분기해 가며 리프 노드까지 도달


🔍 사용 시점

  • WHERE 조건절에 사용되는 컬럼
  • JOIN, ORDER BY, GROUP BY 대상 컬럼
  • PRIMARY KEY, UNIQUE 제약이 있는 컬럼

🧪 MySQL에서 B-Tree 인덱스 생성 예시

-- 단일 컬럼 인덱스 생성 
CREATE INDEX idx_name 
ON customers(name)
; 

-- 다중 컬럼 인덱스 
CREATE INDEX idx_name_email 
ON customers(name, email)
; 

-- PRIMARY KEY도 내부적으로 B-Tree 인덱스 생성됨 
CREATE TABLE users ( 
	id INT PRIMARY KEY, -- 자동 인덱스 생성됨 
    name VARCHAR(50) 
);

✅ B-Tree 인덱스의 특징

특징 설명
정렬된 구조 정렬 기반 검색/범위 조회에 매우 유리
O(log n) 트리 구조이므로 탐색 속도가 매우 빠름
범위 검색 가능 BETWEEN, >, < 등 연산에 최적
Like ‘abc%’ 접두어 검색에 유리 (접미어는 불리)
데이터 변경 시 자동 갱신 INSERT/UPDATE 시 트리 재구성

DB에서는 이렇게 데이터를 관리하고 사용하기 위해 많은 방법을 고안해 사용하고 있다. 

하지만 데이터가 백업되지 않은 상태에서 사용하다가 데이터가 날아간다면 위의 방법들은 아무 소용이 없을 것이다. 

그렇기에 데이터 백업은 DB를 사용하고 관리한다면 기본으로 신경 써야 하는 부분 중 하나라고 생각된다. 

 

🧰 백업(Backup) 

1️⃣ 백업이 왜 필요한가?

이유 설명
데이터 손실 방지 하드웨어 고장, 인재 실수, 바이러스 등에 대비
장애 복구(DR) RDS, 온프레미스 DB 모두 장애 발생 시 복원 필요
보안 위협 대응 랜섬웨어, 해킹 등 외부 위협으로부터 복구 가능
테스트/개발 환경 구성 운영 데이터로부터 안전한 복사본 제공 가능
법적/감사 목적 특정 기간 이상 보관 의무가 있는 경우도 있음

👉 백업은 운영할 때의 필수 요소라고 할 수 있다. 


2️⃣ 백업의 종류

구분 설명 특징
전체 백업(Full Backup) DB 전체를 통째로 백업 복원 간편, 용량 큼
차등 백업(Differential) 마지막 전체 백업 이후 변경된 데이터만 백업 점점 용량 증가, 복원은 빠름
증분 백업(Incremental) 마지막 백업 이후 변경분만 백업 용량 적음, 복원은 오래 걸림
로그 백업 트랜잭션 로그만 백업 장애 시 특정 시점까지 복구 가능
스냅샷(Snapshot) 저장소의 시점 복제본 생성 빠르고 공간 효율적, 파일 시스템/스토리지 단위
물리적 백업 파일 기반으로 백업 (ex. mysqldump, cp) 서버 전체 복사
논리적 백업 SQL로 덤프 (INSERT, CREATE) 이식성 좋음, 느림

3️⃣ RPO와 백업 주기란?

📌 RPO (Recovery Point Objective)

장애 발생 시 데이터 손실을 허용할 수 있는 최대 시간 간격

예시 의미
RPO 1시간 장애 복구 후 1시간치 데이터는 손실 가능
RPO 5분 최대 5분 전까지만 복구하면 됨 → 백업 주기도 5분 단위 필요

📌 RTO (Recovery Time Objective) (참고)

복구까지 걸리는 최대 허용 시간


⏰ 백업 주기 설정 기준 예시

백업 주기 적용 상황
매일 전체 백업 단순한 서비스, 중요도 중간
주 1회 전체 + 매일 증분 대부분의 실무 환경
5분 단위 로그 백업 금융, 거래 시스템 등 RPO가 매우 짧은 경우
스냅샷 30분 간격 클라우드에서 빠르게 복원 가능해야 할 때

4️⃣ 백업 자동화 및 스케줄 관리

✅ CLI 자동화 예시 (MySQL + crontab)

# backup.sh 예시 
mysqldump -u root -p'yourpassword' mydb > /backup/mydb_$(date +%F).sql
# crontab 등록 (매일 새벽 2시 실행) 
0 2 * * * /home/user/backup.sh

✅ PostgreSQL 예시

pg_dump -U postgres mydb > backup_$(date +%F).sql

✅ 클라우드 스케줄러 활용

서비스 기능
AWS RDS 스냅샷 자동화 백업 보존 주기 설정 + 자동 삭제
Google Cloud SQL 백업 일정 UI로 주기 지정 가능
Azure 자동 백업 정책 최대 35일 보존, 정밀 제어 가능

5️⃣ 요약 정리

항목 설명
필요성 장애 복구, 보안 위협, 테스트용, 법적 보관 등
백업 종류 전체, 증분, 차등, 로그, 스냅샷
RPO 복구 시 허용 가능한 데이터 손실 시간
주기 설정 RPO 기반, 일일/분단위/이중화 조합
자동화 방법 스크립트 + crontab or 클라우드 관리 도구

 


본 후기는 [카카오엔터프라이즈x스나이퍼팩토리] 카카오클라우드로 배우는 AIaaS 마스터 클래스 (B-log) 리뷰로 작성 되었습니다.