Performance Guide
시간 복잡도 분석
Big-O 표기법
| 복잡도 | 이름 | 예시 |
|---|
| O(1) | 상수 | 해시맵 조회 |
| O(log n) | 로그 | 이진 탐색 |
| O(n) | 선형 | 배열 순회 |
| O(n log n) | 선형 로그 | 퀵소트, 머지소트 |
| O(n²) | 제곱 | 중첩 루프 |
| O(2ⁿ) | 지수 | 모든 부분집합 |
흔한 비효율 패턴
# Bad: O(n²) - 중첩 루프
function findDuplicates(arr):
for i in range(len(arr)):
for j in range(i+1, len(arr)):
if arr[i] == arr[j]:
return true
return false
# Good: O(n) - 해시셋
function findDuplicates(arr):
seen = set()
for item in arr:
if item in seen:
return true
seen.add(item)
return false
데이터베이스 최적화
N+1 문제
# Bad: N+1 쿼리
users = db.query("SELECT * FROM users")
for user in users:
posts = db.query("SELECT * FROM posts WHERE user_id = ?", user.id)
# Good: JOIN 또는 IN
users = db.query("""
SELECT users.*, posts.*
FROM users
LEFT JOIN posts ON users.id = posts.user_id
""")
# 또는 두 번 쿼리
users = db.query("SELECT * FROM users")
userIds = [u.id for u in users]
posts = db.query("SELECT * FROM posts WHERE user_id IN (?)", userIds)
인덱스 전략
# 자주 검색하는 컬럼에 인덱스
CREATE INDEX idx_users_email ON users(email)
# 복합 인덱스 (순서 중요)
CREATE INDEX idx_posts_user_created ON posts(user_id, created_at)
# 커버링 인덱스
CREATE INDEX idx_users_covering ON users(email, name, status)
# 인덱스가 사용되지 않는 경우
WHERE LOWER(email) = 'test' # 함수 사용
WHERE status != 'active' # 부정 조건
WHERE name LIKE '%test' # 앞 와일드카드
쿼리 최적화
# Bad: SELECT *
SELECT * FROM users WHERE status = 'active'
# Good: 필요한 컬럼만
SELECT id, name, email FROM users WHERE status = 'active'
# Bad: 큰 OFFSET
SELECT * FROM posts ORDER BY created_at LIMIT 20 OFFSET 10000
# Good: Cursor 기반
SELECT * FROM posts
WHERE created_at < ?last_cursor
ORDER BY created_at DESC
LIMIT 20
캐싱 전략
캐시 레이어
요청 → 1. 브라우저 캐시
→ 2. CDN
→ 3. 애플리케이션 캐시 (Redis)
→ 4. 데이터베이스 쿼리 캐시
→ 5. 데이터베이스
캐시 패턴
# Cache-Aside (Lazy Loading)
function getUser(userId):
user = cache.get("user:" + userId)
if user:
return user
user = db.users.findById(userId)
cache.set("user:" + userId, user, ttl=3600)
return user
# Write-Through
function updateUser(userId, data):
user = db.users.update(userId, data)
cache.set("user:" + userId, user)
return user
# Cache Invalidation
function deleteUser(userId):
db.users.delete(userId)
cache.delete("user:" + userId)
TTL 전략
# 데이터 특성별 TTL
CACHE_TTL = {
"user_profile": 3600, # 1시간 (자주 안 바뀜)
"user_session": 1800, # 30분
"product_list": 300, # 5분 (자주 바뀜)
"static_config": 86400, # 24시간
}
비동기 처리
작업 큐
# 동기 처리 (느림)
function signup(user):
createUser(user)
sendWelcomeEmail(user) # 3초
createAnalytics(user) # 2초
return user # 총 5초+
# 비동기 처리 (빠름)
function signup(user):
createUser(user)
queue.enqueue("send_welcome_email", user)
queue.enqueue("create_analytics", user)
return user # 즉시 반환
배치 처리
# Bad: 개별 처리
for item in items:
db.insert(item) # N번 DB 호출
# Good: 배치 처리
db.insertMany(items) # 1번 DB 호출
# 청크 처리 (메모리 관리)
CHUNK_SIZE = 1000
for chunk in chunks(items, CHUNK_SIZE):
db.insertMany(chunk)
메모리 최적화
메모리 누수 방지
# Bad: 이벤트 리스너 누수
function Component:
onMount:
window.addEventListener("resize", this.handleResize)
# cleanup 없음!
# Good: cleanup
function Component:
onMount:
window.addEventListener("resize", this.handleResize)
onUnmount:
window.removeEventListener("resize", this.handleResize)
대용량 데이터 처리
# Bad: 전체 메모리 로드
data = file.readAll() # 10GB 파일 → 메모리 부족
# Good: 스트리밍
for chunk in file.readChunks(1024 * 1024): # 1MB씩
process(chunk)
# Generator 사용
function processLargeData(items):
for item in items:
yield transform(item) # 하나씩 처리
프론트엔드 최적화
번들 최적화
// 코드 스플리팅
import("./heavyModule").then(module => {
module.init()
})
// Tree Shaking
import { used } from "library" // unused는 번들에서 제외
<!-- 이미지 최적화 -->
<img src="image.jpg"
loading="lazy"
srcset="small.jpg 300w, large.jpg 1000w">
렌더링 최적화
# Bad: 불필요한 리렌더
function Parent:
render:
<Child data={this.state.data} />
# Good: 메모이제이션
MemoizedChild = memo(Child)
function Parent:
render:
<MemoizedChild data={this.state.data} />
# 가상화 (긴 목록)
<VirtualList
items={largeList}
itemHeight={50}
renderItem={item => <Item data={item} />}
/>
성능 측정
백엔드 메트릭
# 응답 시간
p50: 50ms # 중앙값
p95: 200ms # 95% 요청
p99: 500ms # 99% 요청
# 처리량
RPS: 1000 # 초당 요청 수
# 에러율
Error Rate < 0.1%
프론트엔드 메트릭
# Core Web Vitals
LCP (Largest Contentful Paint): < 2.5s
FID (First Input Delay): < 100ms
CLS (Cumulative Layout Shift): < 0.1
성능 체크리스트
데이터베이스
캐싱
코드
관련 스킬
code-quality: 코드 최적화 원칙
debugging: 성능 문제 분석