su-tudy 님의 블로그
고급 SQL과 설계 본문
𖤐 SQL 심화 개념 맛보기
마지막 편에서는 서브쿼리, 집합 연산자, 인덱스, 정규화, ERD처럼 한 단계 더 나아간 개념들을 정리한다. 이번 편에서는 각 개념의 핵심과 사용 목적 위주로, 전체 흐름을 가볍게 맛보는 느낌으로 살펴본다.
𖤐 정리 노트
✧ 서브쿼리 (Subquery)
쿼리 안에 또 다른 쿼리를 넣는 것이다. 괄호 안의 쿼리가 먼저 실행되고 그 결과를 바깥 쿼리에서 사용한다.
-- 평균 급여보다 높은 직원 조회
SELECT name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);
▸ EXISTS
서브쿼리의 결과가 한 건이라도 존재하면 TRUE를 반환한다.
-- 주문이 한 건이라도 있는 유저만 조회
SELECT name
FROM users u
WHERE EXISTS (
SELECT 1
FROM orders o
WHERE o.user_id = u.id
);
▸ ANY
서브쿼리 결과 중 하나라도 조건을 만족하면 TRUE다.
-- 어느 부서든 최소 급여보다 높은 직원 조회
SELECT name, salary
FROM employees
WHERE salary > ANY (
SELECT MIN(salary)
FROM employees
GROUP BY dept
);
▸ ALL
서브쿼리 결과 모두 조건을 만족해야 TRUE다.
-- 모든 부서의 최대 급여보다 높은 직원 조회
SELECT name, salary
FROM employees
WHERE salary > ALL (
SELECT MAX(salary)
FROM employees
GROUP BY dept
);
> ANY = 최솟값보다 크면 됨 / > ALL = 최댓값보다도 커야 한다
✧ 집합 연산자
두 SELECT 결과를 합치거나 비교할 때 사용한다. 두 쿼리의 컬럼 수와 데이터 타입이 일치해야 한다.
| 연산자 | 설명 |
UNION |
두 결과 합치기 (중복 제거) |
UNION ALL |
두 결과 합치기 (중복 포함) |
INTERSECT |
두 결과의 교집합 |
EXCEPT |
첫 번째 결과에서 두 번째 결과 빼기 |
-- 서울 고객 + 부산 고객 합치기 (중복 제거)
SELECT name FROM users WHERE city = '서울'
UNION
SELECT name FROM users WHERE city = '부산';
✧ 인덱스 (Index)
테이블에서 데이터를 빠르게 찾기 위한 색인이다. 책의 목차처럼 원하는 데이터의 위치를 미리 정리해 둔 것이라고 보면 된다.
인덱스를 걸면 조회 속도는 빨라지지만, 데이터를 추가/수정/삭제할 때마다 인덱스도 같이 업데이트해야 해서 쓰기 성능은 느려진다. 자주 조회하는 컬럼, WHERE나 JOIN에 자주 쓰이는 컬럼에 거는 게 일반적이다.
-- 인덱스 생성 (중복 허용)
CREATE INDEX idx_name ON users (name);
-- 인덱스 생성 (중복 불허)
CREATE UNIQUE INDEX idx_email ON users (email);
-- 인덱스 삭제
ALTER TABLE users DROP INDEX idx_name;
✧ 정규화 (Normalization)
데이터 중복을 줄이고 이상 현상을 방지하기 위해 테이블을 올바르게 분리하는 과정이다. 주요 정규화 단계는 1NF → 2NF → 3NF로 올라갈수록 중복이 줄어든다.
[정규화 전 - 하나의 테이블에 다 때려넣은 상태]
order_id customer_name customer_phone product price
1 김철수 010-1111-2222 노트북 1200000
2 김철수 010-1111-2222 마우스 30000
3 이영희 010-3333-4444 키보드 80000
문제: 김철수 전화번호가 바뀌면 여러 행을 다 수정해야 함
[정규화 후 - 테이블 분리]
customers: id, name, phone
orders: order_id, customer_id, product, price
✧ ERD (Entity Relationship Diagram)
테이블 간의 관계를 시각적으로 표현한 설계도다. DB를 만들기 전에 구조를 미리 그려보는 용도로 쓴다.
[users] ─────────< [orders] >────────── [products]
id (PK) order_id (PK) id (PK)
name user_id (FK) name
email product_id (FK) price
quantity
| 표기 | 의미 |
| 1 : 1 | 하나에 하나 대응 |
| 1 : N | 하나에 여러 개 대응 (가장 흔함) |
| N : M | 여러 개에 여러 개 대응 (중간 테이블 필요) |
users와 orders는 1:N 관계다. 한 유저가 여러 주문을 할 수 있지만, 하나의 주문은 한 유저에게만 속한다.
𖤐 체크포인트
🚨 서브쿼리 vs JOIN 성능
서브쿼리로 짠 것과 JOIN으로 짠 것이 같은 결과를 낼 수 있는데, 일반적으로 JOIN이 더 빠른 경우가 많다. 서브쿼리는 매 행마다 반복 실행될 수 있기 때문이다.
🚨 주의 — 인덱스는 만능이 아니다
인덱스를 무조건 많이 걸면 쓰기 성능이 떨어진다. 꼭 필요한 컬럼에만 선택적으로 걸어야 한다.
𖤐 오늘의 한 줄 요약
서브쿼리로 쿼리 안에 쿼리를 넣고, 집합 연산자로 결과를 합치고, 인덱스로 조회를 빠르게 한다. 정규화로 테이블 구조를 잘 설계하고, ERD로 관계를 시각화한다.
'DBMS > Part 4. 데이터베이스 고급' 카테고리의 다른 글
| DCL과 TCL (0) | 2024.10.19 |
|---|