운영 서버에서 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>
This commit is contained in:
2026-09-15 23:30:42 +09:00
parent ded12332d5
commit 03eea2098e
56 changed files with 6993 additions and 0 deletions
@@ -0,0 +1,151 @@
# 04단계: 개선 효과 검증
> 인덱스 추가 후 02단계와 **같은 스크립트, 같은 쿼리, 같은 시각**으로 다시 측정해 비교합니다.
모든 명령은 `result/` 디렉터리에서 실행합니다. `params.sql`, `queries/`는 02단계 그대로 두세요.
```bash
cd doc/plan/db/260915-improve-production/result
```
---
## 4-1. 측정 실행
**아래 명령어를 터미널에 복사-붙여넣기해서 실행하세요:**
```bash
zsh run_measure.sh after
```
`after_explain_q*.json` 6개와 `after_perf.txt`가 저장되고 요약이 출력됩니다.
---
## 4-2. EXPLAIN 비교
**아래 명령어를 터미널에 복사-붙여넣기해서 실행하세요:**
```bash
python3 summarize_explain.py baseline after | tee explain_summary.txt
```
**확인할 점:**
| 쿼리 | 기대 결과 |
|---|---|
| q2, q4, q6 (범위형) | `access_type` = `range`, 새 인덱스(`idx_maestro_app_dt` 또는 `idx_maestro_player_app_dt`) 사용, `rows`가 베이스라인보다 크게 감소 |
| q1, q3, q5 (함수형) | 새 인덱스를 써도 날짜 조건은 인덱스로 거르지 못해 `rows` 감소 폭이 작음 → 3-4 쿼리 수정이 필요한 이유 |
> 옵티마이저가 두 새 인덱스 중 어느 쪽을 고를지는 데이터 분포에 따라 다릅니다. 새 인덱스 중 하나를 쓰고 `rows`가 줄었으면 정상입니다.
---
## 4-3. 결과 행 수 비교
인덱스는 조회 결과를 바꾸지 않아야 합니다.
**아래 명령어를 터미널에 복사-붙여넣기해서 실행하세요:**
```bash
rowcount() {
grep -E '^\| === |rows? in set|Empty set' "$1" | paste - - - | grep 'round 2' \
| sed -E 's/ \([0-9.]+ sec\)//g'
}
diff <(rowcount baseline_perf.txt) <(rowcount after_perf.txt) && echo "결과 행 수 동일 ✅"
```
> `@day`가 지난달이라 02와 04 사이에 데이터가 거의 바뀌지 않습니다. 다르게 나오면 그 사이 선생님이 기록을 삭제했는지 확인하세요. (3-0 중복 정리는 `best_record`를 건드리지 않습니다)
---
## 4-4. 실행 시간 비교
**아래 명령어를 터미널에 복사-붙여넣기해서 실행하세요:**
```bash
timing() {
grep -E '^\| === |rows? in set|Empty set' "$1" | paste - - - | grep 'round 2' \
| sed -E 's/\| === round 2: (.*) === \|/\1/; s/\t1 row in set \([0-9.]+ sec\)//'
}
paste <(timing baseline_perf.txt) <(timing after_perf.txt | cut -f2) | tee timing_summary.txt
```
**출력 형식:** `쿼리 이름` · `베이스라인 행 수 (시간)` · `개선 후 행 수 (시간)`
4-2와 4-4-1 결과를 비교표에 옮깁니다.
```bash
cat > comparison.txt << 'EOF'
=== 성능 개선 효과 (운영 DB) ===
측정 기준: params.sql (MaestroID 181, AppID 21, @day ____, @hour ____)
| 쿼리 | access_type (전→후) | rows (전→후) | 서버 시간 ms (전→후, 4-4-1) |
|--------------------|---------------------|----------------|-------------------|
| q1 시간별 · 함수 | ____ → ____ | ____ → ____ | ____ → ____ |
| q2 시간별 · 범위 | ____ → ____ | ____ → ____ | ____ → ____ |
| q3 일간 · 함수 | ____ → ____ | ____ → ____ | ____ → ____ |
| q4 일간 · 범위 | ____ → ____ | ____ → ____ | ____ → ____ |
| q5 월간 · 함수 | ____ → ____ | ____ → ____ | ____ → ____ |
| q6 월간 · 범위 | ____ → ____ | ____ → ____ | ____ → ____ |
참고 (스테이징): rows 5,804 → 1, cost 8.63 → 0.004
참고 (운영 01 사전 측정): 일간 랭킹 index_merge, rows 10,100
결과 행 수 동일 (4-3): [ ] 예 [ ] 아니오
결론:
- 인덱스만의 효과 (q1·q3·q5): ____
- 인덱스 + 쿼리 수정 효과 (q2·q4·q6): ____
EOF
cat comparison.txt
```
---
## 4-4-1. 서버 측 실행 시간 비교 (ANALYZE)
4-4의 시간에는 네트워크 왕복(운영 측정 기준 약 15ms)이 포함됩니다. 02단계 2-4-1과 같은 방법으로 서버 처리 시간을 측정해 비교합니다. (베이스라인: 6개 모두 약 75~80ms)
```bash
{ cat params.sql
for q in queries/*.sql; do
echo "SELECT '=== ${q:t:r} ===';"
printf 'ANALYZE FORMAT=JSON '
cat "$q"
done
} | mariadb -h chocomae.jinaju.com -u jisangs -p chocomae -N -r > after_analyze.txt
python3 summarize_analyze.py after | tee after_analyze_summary.txt
```
```bash
python3 summarize_analyze.py baseline after | tee analyze_summary.txt
```
---
## 4-5. Slow Query Log 확인 (`mysql.slow_log` SELECT 권한 필요)
**아래 명령어를 터미널에 복사-붙여넣기해서 실행하세요:**
```bash
mariadb -h chocomae.jinaju.com -u jisangs -p chocomae -e "
SELECT start_time, query_time, rows_examined, LEFT(sql_text, 120) AS sql_text
FROM mysql.slow_log
WHERE start_time >= NOW() - INTERVAL 1 HOUR
ORDER BY query_time DESC
LIMIT 10;" > after_slow_log.txt
cat after_slow_log.txt
```
- 측정 스크립트의 쿼리도 0.5초를 넘으면 기록됩니다. 운영 앱 쿼리 중 느린 것이 남아 있는지 확인하세요.
- `log_output``TABLE`이 없으면 이 테이블은 비어 있습니다 (02단계 2-1 참고).
---
## 다음 단계
✅ 개선 효과 검증 완료 → **05-checklist.md로 이동**