DB 성능 튜닝 완벽 체크리스트: 느린 쿼리를 10배 빠르게 만드는 방법
데이터베이스 성능을 획기적으로 향상시키는 실전 체크리스트. 인덱스, 쿼리, 설정 최적화까지 모든 것을 다룹니다.
럿지 AI 팀
5분 읽기
목차
DB 성능 튜닝 체크리스트
1단계: 문제 진단
슬로우 쿼리 로그 확인
``
sql
-- 슬로우 쿼리 활성화
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1; -- 1초 이상
-- 로그 확인
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
`
현재 실행 중인 쿼리
`sql
SHOW PROCESSLIST;
-- 상세 정보
SELECT * FROM information_schema.processlist
WHERE command != 'Sleep'
ORDER BY time DESC;
`
2단계: 인덱스 최적화
✅ 체크리스트
- [ ] WHERE 절 컬럼에 인덱스
- [ ] JOIN 컬럼에 인덱스
- [ ] ORDER BY 컬럼에 인덱스
- [ ] 복합 인덱스 순서 최적화
- [ ] 불필요한 인덱스 제거
인덱스 확인
`sql
-- 테이블의 인덱스 목록
SHOW INDEX FROM orders;
-- 사용 안 하는 인덱스
SELECT * FROM sys.schema_unused_indexes;
`
복합 인덱스 순서
`sql
-- ✗ 나쁨
CREATE INDEX idx_bad ON orders(order_date, status);
WHERE status = 'PAID' AND order_date >= '2024-01-01';
-- ✓ 좋음 (선택도 높은 것 먼저)
CREATE INDEX idx_good ON orders(status, order_date);
`
3단계: 쿼리 최적화
SELECT 최적화
`sql
-- ✗ 나쁨
SELECT * FROM orders;
-- ✓ 좋음
SELECT order_id, total_amount FROM orders;
`
JOIN 최적화
`sql
-- ✗ 나쁨 (불필요한 JOIN)
SELECT o.*
FROM orders o
LEFT JOIN members m ON o.member_id = m.member_id;
-- ✓ 좋음
SELECT * FROM orders;
`
WHERE 최적화
`sql
-- ✗ 나쁨 (함수 사용)
WHERE YEAR(order_date) = 2024
-- ✓ 좋음
WHERE order_date >= '2024-01-01' AND order_date < '2025-01-01'
-- ✗ 나쁨 (LIKE 중간 매칭)
WHERE name LIKE '%홍%'
-- ✓ 좋음 (LIKE 앞부분 매칭)
WHERE name LIKE '홍%'
`
LIMIT 활용
`sql
-- ✗ 나쁨
SELECT * FROM orders ORDER BY order_date DESC;
-- ✓ 좋음
SELECT * FROM orders ORDER BY order_date DESC LIMIT 100;
`
4단계: 테이블 설계
정규화
`sql
-- ✗ 나쁨 (데이터 중복)
CREATE TABLE orders (
order_id INT,
member_name VARCHAR(50), -- 중복!
member_address VARCHAR(200) -- 중복!
);
-- ✓ 좋음 (3NF)
CREATE TABLE orders (
order_id INT,
member_id INT,
FOREIGN KEY (member_id) REFERENCES members(member_id)
);
CREATE TABLE members (
member_id INT PRIMARY KEY,
name VARCHAR(50),
address VARCHAR(200)
);
`
데이터 타입 최적화
`sql
-- ✗ 나쁨
status VARCHAR(255)
-- ✓ 좋음
status ENUM('PENDING', 'PAID', 'SHIPPED')
-- ✗ 나쁨
is_active VARCHAR(10)
-- ✓ 좋음
is_active BOOLEAN
`
5단계: 파티셔닝
대용량 테이블
`sql
-- 1억 건 이상 → 파티셔닝 고려
CREATE TABLE orders (
order_id BIGINT,
order_date DATE,
PRIMARY KEY (order_id, order_date)
) PARTITION BY RANGE (YEAR(order_date) * 100 + MONTH(order_date)) (
PARTITION p202401 VALUES LESS THAN (202402),
PARTITION p202402 VALUES LESS THAN (202403),
...
);
`
6단계: 설정 최적화
InnoDB 버퍼 풀
`ini
my.cnf
[mysqld]
전체 RAM의 70-80%
innodb_buffer_pool_size = 8G
CPU 코어 수
innodb_buffer_pool_instances = 8
`
쿼리 캐시 (MySQL 5.7 이하)
`ini
query_cache_type = 1
query_cache_size = 256M
`
커넥션 풀
`ini
max_connections = 500
`
7단계: N+1 문제 해결
문제
`sql
-- 주문 100개 조회
SELECT * FROM orders LIMIT 100;
-- 각 주문마다 회원 정보 (100번!)
SELECT * FROM members WHERE member_id = ?;
`
해결
`sql
-- JOIN으로 한 번에
SELECT o.*, m.*
FROM orders o
LEFT JOIN members m ON o.member_id = m.member_id
LIMIT 100;
`
8단계: 캐싱 전략
Redis 캐싱
`python
자주 조회되는 데이터
product = cache.get(f'product:{product_id}')
if not product:
product = db.query('SELECT * FROM products WHERE id = ?', product_id)
cache.set(f'product:{product_id}', product, ttl=3600)
`
쿼리 결과 캐싱
`python
집계 쿼리 캐싱
stats = cache.get('daily_stats')
if not stats:
stats = db.query('SELECT COUNT(*), SUM(amount) FROM orders ...')
cache.set('daily_stats', stats, ttl=3600)
`
9단계: 모니터링
주요 지표
`sql
-- 슬로우 쿼리 개수
SHOW GLOBAL STATUS LIKE 'Slow_queries';
-- 커넥션 사용률
SHOW STATUS LIKE 'Threads_connected';
SHOW VARIABLES LIKE 'max_connections';
-- 버퍼 풀 사용률
SHOW STATUS LIKE 'Innodb_buffer_pool%';
`
테이블 통계
`sql
-- 테이블 크기
SELECT
table_name,
ROUND(((data_length + index_length) / 1024 / 1024), 2) AS size_mb
FROM information_schema.tables
WHERE table_schema = 'mydatabase'
ORDER BY size_mb DESC;
`
10단계: 정기 유지보수
통계 정보 갱신
`sql
-- 주 1회
ANALYZE TABLE orders;
ANALYZE TABLE members;
`
테이블 최적화
`sql
-- 월 1회
OPTIMIZE TABLE orders;
`
성능 향상 전후 비교
Before
`sql
SELECT * FROM orders
WHERE status = 'PAID' AND order_date >= '2024-01-01';
-- 실행 시간: 5초
-- EXPLAIN: type=ALL, rows=1,000,000
`
After (최적화 적용)
`sql
-- 1. 인덱스 추가
CREATE INDEX idx_status_date ON orders(status, order_date);
-- 2. 필요한 컬럼만 조회
SELECT order_id, total_amount
FROM orders
WHERE status = 'PAID' AND order_date >= '2024-01-01'
LIMIT 100;
-- 실행 시간: 0.01초 (500배 향상!)
-- EXPLAIN: type=ref, rows=100, key=idx_status_date
``최종 체크리스트
인덱스
- [ ] WHERE 절 인덱스
- [ ] JOIN 인덱스
- [ ] 복합 인덱스 순서
- [ ] 불필요한 인덱스 제거
쿼리
- [ ] SELECT * 제거
- [ ] LIMIT 사용
- [ ] 함수 제거
- [ ] N+1 해결
설계
- [ ] 정규화 (3NF)
- [ ] 데이터 타입 최적화
- [ ] 파티셔닝 (대용량)
운영
- [ ] 슬로우 쿼리 모니터링
- [ ] 정기 ANALYZE
- [ ] 정기 OPTIMIZE
더 배우기
김영한의 실전 데이터베이스
- 성능 튜닝 심화
- 대용량 처리
- 실전 최적화
---
**태그**: #DB성능튜닝 #쿼리최적화 #MySQL성능 #체크리스트 #최적화가이드
L
럿지 AI 팀
AI 기술과 비즈니스 혁신을 선도하는 럿지 AI의 콘텐츠 팀입니다.
관련 포스트
비즈니스
탄탄한 DB 아키텍처로 시리즈 B 200억 투자 유치 성공
VC들이 가장 주목한 기술 경쟁력, 확장 가능한 DB 설계로 기업 가치 3배 인정받은 스타트업 사례입니다.
•3분 읽기
비즈니스
DB 설계로 스타트업 스케일링 성공: 유저 10배 증가 무장애 운영
처음부터 제대로 된 DB 설계로 유저 100만 돌파까지 리팩토링 없이 성공한 스타트업 사례입니다.
•4분 읽기
비즈니스
DB 최적화로 연간 서버 비용 12억 절감: 클라우드 비용 80% 감소
올바른 DB 설계와 최적화로 AWS 비용을 80% 절감하고 연간 12억을 아낀 중견 기업 사례입니다.
•4분 읽기