데이터가 많아지면(회사 채팅방에서 데드라인 얘기 나오는 것처럼) SELECT나 데이터 처리 쿼리가 느려지기 시작해. 주요 원인은 이거야:
- 인덱스 없음. PostgreSQL이 쿼리 실행할 때 테이블 전체를 스캔해야 하면(이걸 "Seq Scan" — 시퀀셜 스캔이라고 해), 쿼리가 훨씬 오래 걸릴 수 있어.
- 비효율적인 SQL 쿼리. 쿼리를 최적화 생각 안 하고 짜면, 인덱스가 있어도 실무에서 고생할 수 있어. 예를 들어
WHERE에서 중요한 조건 빼먹었어? 그럼 쿼리 오래 걸릴 준비해야지. - 한 테이블에 데이터가 너무 많음. 예를 들어, 모든 연도 판매 데이터를 한 번에 분석하려고 하면, 인덱스만으로도 부족할 수 있어.
근데 걱정하지 마! 이럴 때 쓸 수 있는 두 가지 검증된 방법이 있어: 인덱싱이랑 파티셔닝.
쿼리 속도 올리기 위한 인덱스 사용
인덱스 만드는 간단한 예시 보여줄게:
CREATE INDEX idx_sales_date ON sales(transaction_date);
- 여기서
idx_sales_date는 인덱스 이름이야(원하는 대로 지어도 되지만, 의미 있게 짓는 게 좋아). ON sales(transaction_date)— 어떤 테이블, 어떤 컬럼에 인덱스 만드는지 지정하는 거야.
이 인덱스는 transaction_date 컬럼으로 자주 필터링할 때 특히 유용해.
이 인덱스 덕분에 빨라지는 쿼리 예시:
SELECT *
FROM sales
WHERE transaction_date BETWEEN '2023-01-01' AND '2023-12-31';
복합 키 인덱싱
쿼리에서 여러 컬럼(region이랑 product_id 같은 거) 조합을 자주 쓰면, 복합 인덱스 만드는 것도 고려해봐:
CREATE INDEX idx_sales_region_product ON sales(region, product_id);
이제 이런 쿼리들이 훨씬 빨라져:
SELECT *
FROM sales
WHERE region = 'North America' AND product_id = 42;
유니크 인덱스 사용하기
유니크 인덱스는 검색만 빠르게 해주는 게 아니라, 컬럼 값의 유일성도 보장해줘. 예를 들어:
CREATE UNIQUE INDEX idx_unique_customer_email ON customers(email);
이제 같은 이메일 가진 고객을 실수로 두 번 등록할 수 없어.
분석 함수용 인덱싱
SUM, COUNT, AVG 같은 데이터 분석 함수도 인덱스를 활용해서 더 빨리 계산할 수 있어. 예시:
CREATE INDEX idx_sales_amount ON sales(amount);
쿼리:
SELECT SUM(amount)
FROM sales
WHERE transaction_date >= '2023-01-01';
이 인덱스 덕분에 쿼리가 더 빨라질 거야.
대용량 데이터 처리를 위한 테이블 파티셔닝
테이블 파티셔닝은 큰 테이블을 더 작은 논리적 조각(파티션)으로 나누는 거야. 예를 들어 sales 테이블을 연도별로 나눌 수 있어: sales_2021, sales_2022 등등.
이거 어렵다고 생각해? 사실 PostgreSQL이 생각보다 쉽게 해줘.
파티셔닝 종류
- 범위 파티셔닝 (
Range Partitioning). 예를 들어 날짜처럼, 값의 범위로 데이터 나누기. - 리스트 파티셔닝 (
List Partitioning). 예를 들어 지역처럼, 정확한 값으로 데이터 나누기. - 해시 파티셔닝 (
Hash Partitioning). 해시 함수로 데이터 나누기(직접 쓸 일은 드물어).
파티셔닝 테이블 만들기
연도별로 파티셔닝된 판매 테이블 만들어보자.
CREATE TABLE sales (
id SERIAL PRIMARY KEY,
transaction_date DATE NOT NULL,
amount NUMERIC,
region TEXT
) PARTITION BY RANGE (transaction_date);
이제 연도별 파티션을 만들어보자:
CREATE TABLE sales_2021 PARTITION OF sales
FOR VALUES FROM ('2021-01-01') TO ('2022-01-01');
CREATE TABLE sales_2022 PARTITION OF sales
FOR VALUES FROM ('2022-01-01') TO ('2023-01-01');
날짜로 필터링하는 쿼리는 자동으로 해당 파티션만 사용해. EXPLAIN 명령어로 쉽게 확인할 수 있어.
파티셔닝 예시
2021년 판매만 합산하는 쿼리는 이렇게 생겼을 거야:
SELECT SUM(amount)
FROM sales
WHERE transaction_date BETWEEN '2021-01-01' AND '2021-12-31';
보다시피, PostgreSQL은 전체 테이블이 아니라 sales_2021 파티션만 읽어.
예시: 지역별 메트릭 계산 최적화
예를 들어, 지역별로 총 판매액을 계산하고 싶다고 해보자. 인덱스랑 파티션 없으면 진짜 오래 걸려. 먼저 region 컬럼에 인덱스 만들어보자:
CREATE INDEX idx_sales_region ON sales(region);
쿼리:
SELECT region, SUM(amount)
FROM sales
GROUP BY region;
이제 인덱스 덕분에 처리 속도가 빨라져.
예시: 시간 데이터 파티셔닝
트랜잭션이나 로그처럼 시간 데이터는 월별로 파티션을 나누는 게 좋아. 예를 들어:
CREATE TABLE sales_monthly PARTITION BY RANGE (transaction_date);
CREATE TABLE sales_jan_2023 PARTITION OF sales_monthly
FOR VALUES FROM ('2023-01-01') TO ('2023-02-01');
쿼리:
SELECT SUM(amount)
FROM sales_monthly
WHERE transaction_date >= '2023-01-01' AND transaction_date < '2023-02-01';
이렇게 하면 PostgreSQL이 sales_jan_2023 파티션만 읽어서 더 빨라져.
예시: 인덱싱과 파티셔닝 같이 쓰기
인덱싱이랑 파티셔닝을 같이 쓰면 성능을 극대화할 수 있어. 예를 들어, 각 파티션 안에 인덱스를 만들 수도 있어. 예시:
CREATE INDEX idx_sales_amount_jan_2023 ON sales_jan_2023(amount);
흔한 실수 피하는 법
성능 문제의 많은 원인은 인덱스나 파티셔닝을 잘못 써서 생겨. 예를 들어:
- 인덱스가 너무 많으면 INSERT 작업이 느려질 수 있어.
- 파티션은 균등하게 데이터가 들어가게 설계해야 해. 너무 작거나 너무 큰 파티션은 성능을 떨어뜨려.
- 최적화하기 전에 성능 분석(
EXPLAIN ANALYZE)을 안 해보는 건, 자동차 고치면서 보닛도 안 열어보는 거랑 똑같아.
항상 네 최적화가 실제로 속도 향상에 도움이 되는지 체크하고, 실험하는 걸 두려워하지 마!
GO TO FULL VERSION