Files
chocomae/doc/plan/db/260915-improve-production/07-post-analysis.md
T
jisangs 03eea2098e 운영 서버에서 DB index 적용 작업 진행
- 01~07 작업 문서를 운영 측정값 기준으로 정리 (문서의 DB 비밀번호 삭제)
- app_highest_record 중복 8,795행 점수 기준 정리, 인덱스 5개 + UNIQUE 키 2개 추가
- 02·04 공통 측정 스크립트와 측정 결과, comparison.txt 추가
- 서버 처리 시간 18~292배 단축, 결과 행 수 동일
- 운영 데이터 백업과 권한(비밀번호 해시) 파일은 커밋에서 제외

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 23:30:42 +09:00

171 lines
5.6 KiB
Markdown

# 07단계: 사후 분석 및 최적화
> 운영 서버 적용 후 실제 성능을 분석하고 추가 최적화를 검토합니다.
---
## 📊 실제 성능 측정 결과
### 운영 DB에서 측정한 개선율
`comparison.txt`(04단계)의 값을 옮겨 적었습니다 (2026-09-15). 6개 쿼리 전체 값은 [result/comparison.txt](result/comparison.txt)를 참고하세요.
| 항목 | 베이스라인 (02) | 개선 후 (04) | 개선율 | 상태 |
|---|---|---|---|---|
| **EXPLAIN rows (q2 시간별·범위)** | 10,103 | 22 | 459배 ⬇️ | [x] 확인 |
| **EXPLAIN rows (q4 일간·범위)** | 10,103 | 99 | 102배 ⬇️ | [x] 확인 |
| **EXPLAIN rows (q3 일간·함수)** | 10,103 | 5,851 | 1.7배 ⬇️ | [x] 확인 |
| **서버 처리 시간 (q4, ANALYZE)** | 75.2ms | 0.47ms | 161배 ⬇️ | [x] 확인 |
| **서버 처리 시간 (q3 일간·함수, ANALYZE)** | 75.3ms | 2.44ms | 31배 ⬇️ | [x] 확인 |
| **느린 쿼리 수 (0.5초 이상)** | 측정 안 함 (당시 기준 3초·파일 로그) | 앱 쿼리 0건 (작업 후 1시간, 작업 SQL 5건만) | - | [ ] 24시간 후 재확인 |
> 참고: 01단계 사전 측정의 일간 랭킹(함수형)은 `index_merge`, rows 10,100이었습니다.
>
> MariaDB 10.11의 `EXPLAIN FORMAT=JSON`에는 cost 필드가 없어 스테이징의 cost 수치와 직접 비교할 수 없습니다. rows와 실행 시간으로 비교하고, 실제 실행 통계가 필요하면 `ANALYZE FORMAT=JSON <쿼리>`의 `r_rows`, `r_total_time_ms`를 사용하세요 (쿼리를 실제로 실행함).
### 저장된 파일
```
result/
├── premeasure_*.txt, premeasure_*.json ← 01 사전 측정
├── baseline_explain_q*.json ← 02 EXPLAIN
├── baseline_perf.txt ← 02 실행 시간
├── backup_app_highest_dup_rows.sql ← 03 삭제 행 백업
├── add_indexes_result.txt ← 03 인덱스 추가 결과
├── after_explain_q*.json ← 04 EXPLAIN
├── after_perf.txt ← 04 실행 시간
├── explain_summary.txt, timing_summary.txt
└── comparison.txt
```
---
## 🔍 성능 분석
### 쿼리 응답 시간 추이 (24시간 모니터링)
```
시간대별 성능:
- 평상시: _____ ms
- 피크 시간: _____ ms
- 최고 응답 시간: _____ ms
느린 쿼리 로그:
- 0.5초 이상: _____ 개 (개선 전: _____)
- 1초 이상: _____ 개 (개선 전: _____)
- 5초 이상: _____ 개 (개선 전: _____)
```
---
## 📈 비즈니스 영향
| 지표 | 개선 전 | 개선 후 | 변화 |
|---|---|---|---|
| 동시 사용자 | _____ | _____ | _____ |
| 평균 응답 시간 | _____ ms | _____ ms | _____ ms |
| 실패율 | _____ % | _____ % | _____ % |
| CPU 사용률 | _____ % | _____ % | _____ % |
| 메모리 사용률 | _____ % | _____ % | _____ % |
---
## ✅ 성공 여부 판단
### 성공 기준
- [ ] 범위형 쿼리(q2·q4·q6)의 rows가 베이스라인 대비 대폭 감소 (목표: 조회 기간의 실제 기록 수 수준)
- [ ] 느린 쿼리 대폭 감소
- [ ] 결과 행 수 변화 없음, 최고기록 화면 정상
- [ ] 서비스 가용성 100% 유지
- [ ] 사용자 불만 없음
### 결론
```
[ ] 성공: 모든 기준 달성, 운영 정상화
[ ] 부분 성공: 대부분 달성, 모니터링 계속
[ ] 실패: 목표 미달, 추가 최적화 필요
```
---
## 🔧 추가 최적화 제안
### 단계별 추가 개선
#### **1단계: 쿼리 최적화 (안 1)**
- [ ] 함수 제거 쿼리 적용 (03단계 3-4, Stage에서 수정 완료한 코드 배포)
- [ ] 예상 효과: 04단계의 함수형↔범위형 비교값(q1↔q2, q3↔q4, q5↔q6) 참고
#### **2단계: 집계 테이블 도입 (안 2)**
- [ ] daily_best_record, daily_typing_exam_record 생성
- [ ] 예상 효과: 히스토리/랭킹 조회 극적 개선
#### **3단계: 아카이빙 (안 3)**
- [ ] 13개월 이전 기록 아카이빙
- [ ] 예상 효과: 테이블 크기 감소, 백업 시간 단축
- [ ] 참고: 월 적재량이 전년 대비 약 2.1배로 늘고 있음 (01 사전 측정)
#### **4단계: 애플리케이션 최적화 (안 5)**
- [ ] N+1 쿼리 제거
- [ ] SQL Injection 보안 강화
- [ ] 최고기록 저장을 `INSERT ... ON DUPLICATE KEY UPDATE`로 변경 (UNIQUE 키 활용, 동시 저장 시 더 좋은 기록 유지)
- [ ] 예상 효과: 동시 사용자 처리량 2~3배 향상
---
## 📋 모니터링 계획
### 지속적 모니터링 (24시간 이후)
`mysql.slow_log` SELECT 권한이 필요하고, `log_output``TABLE`이 있어야 합니다. 조회가 끝나면 05단계 사후 작업대로 slow query log 설정을 원래 값으로 복원하세요.
```bash
# 일일 성능 리포트
mariadb -h chocomae.jinaju.com -u jisangs -p chocomae -e "
SELECT
DATE_FORMAT(start_time, '%Y-%m-%d %H:00:00') AS hour,
COUNT(*) AS slow_query_count,
AVG(query_time) AS avg_time,
MAX(query_time) AS max_time
FROM mysql.slow_log
WHERE start_time >= CURDATE()
GROUP BY hour
ORDER BY hour;
"
```
---
## 📝 최종 보고서 항목
1. **실행 요약**
- 작업 목표 및 결과
- 성과 지표
2. **기술 분석**
- EXPLAIN 개선 결과
- 실행 시간 비교
- 중복 정리 결과 (삭제 행 수, 백업 파일)
3. **비즈니스 임팩트**
- 사용자 경험 개선
- 서버 비용 절감 효과
4. **추가 제안**
- 다음 단계 최적화 계획
- 예상 추가 효과
---
## 🎯 다음 단계
- [ ] 스테이징에서 안 2 (집계 테이블) 테스트
- [ ] 운영 DB 추가 최적화 검토
- [ ] 팀 회의에서 결과 공유
- [ ] 성능 모니터링 대시보드 구축
---
**운영 서버 성능 개선 프로젝트 완료!** 🎉