Files
chocomae/doc/plan/db/260915-improve-production/04-verify.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

5.2 KiB

04단계: 개선 효과 검증

인덱스 추가 후 02단계와 같은 스크립트, 같은 쿼리, 같은 시각으로 다시 측정해 비교합니다.

모든 명령은 result/ 디렉터리에서 실행합니다. params.sql, queries/는 02단계 그대로 두세요.

cd doc/plan/db/260915-improve-production/result

4-1. 측정 실행

아래 명령어를 터미널에 복사-붙여넣기해서 실행하세요:

zsh run_measure.sh after

after_explain_q*.json 6개와 after_perf.txt가 저장되고 요약이 출력됩니다.


4-2. EXPLAIN 비교

아래 명령어를 터미널에 복사-붙여넣기해서 실행하세요:

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. 결과 행 수 비교

인덱스는 조회 결과를 바꾸지 않아야 합니다.

아래 명령어를 터미널에 복사-붙여넣기해서 실행하세요:

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. 실행 시간 비교

아래 명령어를 터미널에 복사-붙여넣기해서 실행하세요:

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 결과를 비교표에 옮깁니다.

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)

{ 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
python3 summarize_analyze.py baseline after | tee analyze_summary.txt

4-5. Slow Query Log 확인 (mysql.slow_log SELECT 권한 필요)

아래 명령어를 터미널에 복사-붙여넣기해서 실행하세요:

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_outputTABLE이 없으면 이 테이블은 비어 있습니다 (02단계 2-1 참고).

다음 단계

개선 효과 검증 완료 → 05-checklist.md로 이동