운영 서버에서 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:
@@ -0,0 +1,127 @@
|
||||
# 06단계: 롤백 계획
|
||||
|
||||
> 문제 발생 시 인덱스를 삭제하고, 필요하면 중복 정리 전 상태로 되돌립니다.
|
||||
>
|
||||
> ⚠️ 작업용 `jisangs` 계정은 2026-09-15에 삭제했습니다. 이 문서의 `-u jisangs` 명령은 관리자 계정으로 바꿔 실행하세요.
|
||||
|
||||
모든 명령은 `result/` 디렉터리에서 실행합니다.
|
||||
|
||||
---
|
||||
|
||||
## 🚨 긴급 상황 대응
|
||||
|
||||
### 1. 진행 중인 ALTER 중단
|
||||
|
||||
```bash
|
||||
mariadb -h chocomae.jinaju.com -u jisangs -p chocomae -e "SHOW PROCESSLIST;" | grep ALTER
|
||||
|
||||
# 첫 번째 열(Id)의 값을 넣어 실행
|
||||
mariadb -h chocomae.jinaju.com -u jisangs -p chocomae -e "KILL QUERY <Id>;"
|
||||
```
|
||||
|
||||
> 온라인 DDL을 중단하면 그 인덱스만 만들어지지 않고 테이블 데이터는 그대로입니다. 내 계정이 실행한 쿼리는 별도 권한 없이 중단할 수 있습니다.
|
||||
|
||||
### 2. 인덱스 삭제
|
||||
|
||||
```bash
|
||||
mariadb -h chocomae.jinaju.com -u jisangs -p chocomae << 'EOF'
|
||||
-- 모든 인덱스 삭제
|
||||
ALTER TABLE best_record DROP INDEX IF EXISTS idx_maestro_app_dt;
|
||||
ALTER TABLE best_record DROP INDEX IF EXISTS idx_maestro_player_app_dt;
|
||||
ALTER TABLE typing_exam_record DROP INDEX IF EXISTS idx_maestro_writing_dt;
|
||||
ALTER TABLE typing_exam_record DROP INDEX IF EXISTS idx_maestro_player_writing_dt;
|
||||
ALTER TABLE license_score DROP INDEX IF EXISTS idx_maestro_player_dt;
|
||||
ALTER TABLE app_highest_record DROP INDEX IF EXISTS uk_maestro_player_app;
|
||||
ALTER TABLE typing_exam_highest_record DROP INDEX IF EXISTS uk_maestro_player_writing;
|
||||
EOF
|
||||
```
|
||||
|
||||
> UNIQUE 키 2개는 성능과 무관하므로, 성능 문제로 롤백할 때는 남겨 두어도 됩니다. 남겨 두면 중복이 다시 생기지 않습니다.
|
||||
|
||||
---
|
||||
|
||||
## 중복 정리 되돌리기 (필요할 때만)
|
||||
|
||||
삭제한 행은 같은 조합의 **덜 좋은 기록**이라 보통 되돌릴 필요가 없습니다. 되돌려야 하면 UNIQUE 키를 먼저 삭제한 뒤 03단계 3-0-2의 백업 파일을 실행합니다. (INSERT 권한 — jisangs에 임시 부여됨)
|
||||
|
||||
```bash
|
||||
mariadb -h chocomae.jinaju.com -u jisangs -p chocomae -e "
|
||||
ALTER TABLE app_highest_record DROP INDEX IF EXISTS uk_maestro_player_app;"
|
||||
|
||||
mariadb -h chocomae.jinaju.com -u jisangs -p chocomae < backup_app_highest_dup_rows.sql
|
||||
|
||||
mariadb -h chocomae.jinaju.com -u jisangs -p chocomae -e "
|
||||
SELECT COUNT(*) AS total_rows FROM app_highest_record;"
|
||||
```
|
||||
|
||||
> 백업 파일은 원래 ID 그대로 INSERT하므로 기존 행과 충돌하지 않습니다. 복원 후 `total_rows`는 3-0-3 삭제 전 행 수(그 사이 새로 저장된 기록 제외)와 같아야 합니다.
|
||||
|
||||
---
|
||||
|
||||
## 전체 백업에서 복원 (최후의 수단)
|
||||
|
||||
운영 DB는 AWS RDS가 아니라 **EC2의 Docker MariaDB**입니다. 인덱스 문제는 DROP INDEX로 충분하므로 데이터 손상이 있을 때만 사용하세요. **백업 이후 저장된 게임 기록은 모두 사라집니다.**
|
||||
|
||||
### 방법 1: 덤프 파일 복원
|
||||
|
||||
```bash
|
||||
# EC2 서버의 MariaDB 컨테이너 안에서 관리자 계정으로 실행
|
||||
mariadb -u <관리자> -p chocomae < backup_2026-09-15.sql
|
||||
```
|
||||
|
||||
### 방법 2: EBS 스냅샷 복원
|
||||
|
||||
1. AWS 콘솔 → EC2 → 스냅샷에서 작업 전 스냅샷 선택
|
||||
2. 스냅샷으로 볼륨 생성 (EC2 인스턴스와 같은 가용 영역)
|
||||
3. MariaDB 컨테이너 중지 → 기존 데이터 볼륨 분리 → 새 볼륨 연결·마운트
|
||||
4. 컨테이너 시작 후 접속 확인
|
||||
|
||||
### 복제 상태 확인 (복제를 사용 중인 경우, 관리자 계정)
|
||||
|
||||
```sql
|
||||
SHOW MASTER STATUS;
|
||||
SHOW REPLICA STATUS\G
|
||||
```
|
||||
|
||||
### 서비스 정상 확인
|
||||
- 웹 서비스 접속 테스트
|
||||
- 타이핑 게임 플레이 테스트 (결과 저장, 최고기록 표시)
|
||||
- 랭킹 조회 테스트
|
||||
|
||||
---
|
||||
|
||||
## 문제 원인 분석
|
||||
|
||||
| 증상 | 원인 | 대응 |
|
||||
|---|---|---|
|
||||
| 인덱스 생성 실패 | 디스크 부족 | DROP INDEX + 디스크 정리 |
|
||||
| `Duplicate entry ... for key 'uk_...'` | 3-0 이후 새 중복 발생 | 3-0-2·3-0-3 다시 실행 후 `add_indexes.sql` 재실행 (이미 만든 인덱스는 건너뜀) |
|
||||
| 서비스 느려짐 | 옵티마이저가 새 인덱스를 잘못 선택, 통계 부정확 | `ANALYZE TABLE best_record;` (관리자) → 그래도 느리면 해당 인덱스 DROP |
|
||||
| 최고기록 화면 값 이상 | 중복 정리 결과 | 백업 파일에서 해당 조합 확인, 필요하면 "중복 정리 되돌리기" |
|
||||
| 복제 지연·오류 | 복제 서버에서 DDL 적용 중 또는 실패 | `SHOW REPLICA STATUS`로 확인 |
|
||||
|
||||
---
|
||||
|
||||
## 복구 후 확인
|
||||
|
||||
```bash
|
||||
# 테이블 상태 확인
|
||||
mariadb -h chocomae.jinaju.com -u jisangs -p chocomae -e "
|
||||
SHOW INDEXES FROM best_record;
|
||||
SELECT COUNT(*) FROM best_record;
|
||||
"
|
||||
```
|
||||
|
||||
성능 확인은 `zsh run_measure.sh after`로 다시 측정해 `baseline_perf.txt`와 비교합니다. 기존 `after_*` 파일을 덮어쓰므로 먼저 다른 폴더로 옮기세요.
|
||||
|
||||
---
|
||||
|
||||
## 문제 발생 시 연락
|
||||
|
||||
- **팀 리더**: [연락처]
|
||||
- **DBA**: [연락처]
|
||||
- **운영팀**: [연락처]
|
||||
|
||||
---
|
||||
|
||||
**롤백은 최후의 수단입니다. 충분한 검토 후 신중하게 진행하세요.** ⚠️
|
||||
Reference in New Issue
Block a user