# 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로 이동**