데이터베이스 최적화: 쿼리와 인덱싱
개발팀
2분 읽기
데이터베이스SQL성능
데이터베이스 최적화: 쿼리와 인덱싱
데이터베이스 최적화는 애플리케이션 성능의 핵심 요소입니다.
인덱싱 전략
기본 인덱스 생성
-- 단일 열 인덱스
CREATE INDEX idx_users_email ON users(email);
-- 복합 인덱스
CREATE INDEX idx_orders_user_date ON orders(user_id, created_at);
-- 유니크 인덱스
CREATE UNIQUE INDEX idx_users_email_unique ON users(email);
인덱스 선택 기준
- 자주 검색되는 열: WHERE 절에 자주 사용
- 정렬 열: ORDER BY에 사용되는 열
- 조인 열: JOIN 조건에 사용되는 열
- 선택도 높은 열: 중복 값이 적은 열
쿼리 최적화
N+1 문제 해결
// 나쁜 예: N+1 쿼리
const users = await User.findAll();
for (const user of users) {
user.posts = await Post.findByUserId(user.id); // N개의 쿼리
}
// 좋은 예: JOIN 사용
const users = await User.findAll({
include: 'posts' // 1개의 쿼리로 해결
});
필요한 열만 선택
-- 나쁜 예
SELECT * FROM users WHERE id = 1;
-- 좋은 예
SELECT id, name, email FROM users WHERE id = 1;
쿼리 실행 계획 분석
-- MySQL
EXPLAIN SELECT * FROM users WHERE email = 'test@example.com';
-- PostgreSQL
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'test@example.com';
캐싱 전략
// Redis를 사용한 캐싱
async function getUserWithCache(userId) {
const cached = await redis.get(`user:${userId}`);
if (cached) return JSON.parse(cached);
const user = await User.findById(userId);
await redis.set(`user:${userId}`, JSON.stringify(user), 'EX', 3600);
return user;
}
파티셔닝
-- 날짜 기반 파티셔닝
CREATE TABLE logs (
id INT,
created_at DATE,
message TEXT
) PARTITION BY RANGE (YEAR(created_at)) (
PARTITION p2023 VALUES LESS THAN (2024),
PARTITION p2024 VALUES LESS THAN (2025)
);
성능 모니터링
슬로우 쿼리 로그
-- MySQL에서 슬로우 쿼리 로깅 활성화
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 2;
최적화 체크리스트
- 필요한 인덱스 생성 여부 확인
- N+1 쿼리 문제 해결
- 쿼리 실행 계획 검토
- 캐싱 적용 가능성 검토
- 테이블 파티셔닝 필요성 검토
- 슬로우 쿼리 모니터링
데이터베이스 최적화는 지속적인 모니터링과 개선이 필요합니다.