본문 바로가기

서버 관리

[MySQL] MyISAM과 InnoDB 스토리지 엔진 비교 및 복구 방법 정리

서버를 운영하다 보면 갑자기 MySQL에서 "table is crashed"나 "page corruption" 같은 오류 메시지를 된다. 그때마다 얼빵하게 찾아보고 있어서, 게시글로 정리 해둡니다. 당장 복구해야되니까, 일단 살리고 보자해서 깊게 안봤는데 시간날 때 정리해 둘려고 만들었다. myi, myd는 왜 섞여있는지.. idb는 뭔지.

 

1. MyISAM과 InnoDB 기본 특성 비교

일단 이 두 놈이 뭔지 알아야 할 것 같다. 파일이름부터 다른데 뭐가 다른 걸까?

파일 구조 보면 바로 알 수 있음

서버 디렉토리 보면 이런 파일들이 있다.

MyISAM: .MYD(데이터)랑 .MYI(인덱스) 두 개로 나뉘어 있음

InnoDB: .ibd 확장자 하나로 다 처리함

-rw-rw---- 1 mysql mysql     3428352 2025-05-17 12:26 board_history.MYI
-rw-rw---- 1 mysql mysql     8667840 2025-05-17 12:26 board_history.MYD
-rw-rw---- 1 mysql mysql      163840 2025-05-17 12:28 user_login.ibd
-rw-rw---- 1 mysql mysql      180224 2025-05-17 12:29 user_stats.ibd
-rw-rw---- 1 mysql mysql    41025536 2025-05-17 12:30 board_posts.MYI
-rw-rw---- 1 mysql mysql   595096528 2025-05-17 12:30 board_posts.MYD
-rw-rw---- 1 mysql mysql   205520896 2025-05-17 12:30 board_attachments.ibd

 

 

 

 

이 차이점부터 알고 있으면 어떤 테이블이 뭔지 구분할 수 있다. 핵심적인 차이는 이렇다.

MySQL 5.5부터는 MyISAM에서 InnoDB로 기본 엔진이 바뀌었다. 그냥 따라가면 된다.

특성 MyISAM InnoDB 승자
트랜잭션 지원 x o InnoDB
외래키 제약조건 x o InnoDB
락(Lock) 방식 테이블 단위 행 단위 InnoDB
COUNT(*) 쿼리 속도 매우 빠름 전체 스캔 필요 MyISAM
메모리 사용량 적음 많음 MyISAM
크래시 복구 취약함 강력함 InnoDB

 

2. 내 테이블이 뭘 쓰는지 보려면

"그래서 내 테이블은 뭘 쓰고 있지?" 궁금하면 요렇게 보면 된다

SHOW TABLE STATUS FROM 데이터베이스명 WHERE Name = '테이블명';

 

 

전체 다 한번에 보고싶으면

SELECT TABLE_NAME, ENGINE, TABLE_ROWS, 
       ROUND((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024, 2) AS 'Size (MB)'
FROM information_schema.TABLES 
WHERE TABLE_SCHEMA = '데이터베이스명'
ORDER BY (DATA_LENGTH + INDEX_LENGTH) DESC;

 

이거 하면 테이블 이름, 엔진 타입, 행 수, 크기까지 다 나와서 좋다.

 

3. 문제 생겼을 때 뜨는 오류 메시지들

 

두 엔진은 각자 다른 오류 메시지를 뱉는다. 실제로 볼 수 있는 메시지들

MyISAM  메시지

[ERROR] mysqld: Table './mydb/board_posts' is marked as crashed and should be repaired
[Warning] Checking table: './mydb/board_posts'

InnoDB 메시지

[ERROR] InnoDB: Database page corruption on disk or a failed file read of tablespace mydb/user_stats page [page id: space=117, page number=2102334]. You may have to recover from a backup.
[Note] InnoDB: Page dump in ascii and hex (16384 bytes):

 

벌써 둘의 메시지부터 느낌이 다르다. MyISAM은 "고쳐라"라고 하는데, InnoDB는 "백업에서 복구해야 할 수도 있다"라고 으름장을 놓는다.

 

4. 문제 생겼을 때 복구 과정

MyISAM 자동 복구

MyISAM은 문제 생기면 MySQL 설정(myisam_recover_options)에 따라 자동 복구를 시도한다.

# my.cnf 파일 설정 예시
[mysqld]
myisam_recover_options=BACKUP,FORCE

설정할 수 있는 옵션

  • BACKUP: 복구 전에 .BAK 파일로 백업해놓음
  • FORCE: 복구 과정에서 에러 무시하고 밀어붙임
  • QUICK: 빠르게 복구 (데이터 날아갈 수도 있음)
  • DEFAULT: 백업 없이 그냥 복구

기본적으로 테이블 깨지면 MySQL은 다음 시작할 때 자동으로 복구 시도한다. 로그에서 Checking table 메시지 보이면 그게 복구 중인 거다.

InnoDB 자동 복구

InnoDB는 더 복잡하게 돌아간다. 세 가지 방법으로 데이터를 보호한다.

  1. 더블라이트 버퍼
    • 디스크에 쓰기 전에 따로 복사본 만들어둠
    • 이거 때문에 중간에 쓰다가 끊겨도 살릴 수 있음
  2. 체크섬 검증
    • 페이지마다 체크섬 넣어서 손상됐는지 확인함
    • 뭔가 이상하면 바로 알 수 있음
  3. 트랜잭션 로그
    • 뭐 하기 전에 로그에 기록해둠 (선행 로깅)
    • 서버 터져도 재시작하면 커밋된 거 자동 적용

근데 InnoDB는 페이지 깨지면 보통 자동 복구보다는 백업에서 복원하라고 한다. 좀 더 신중한 놈이다.

 

5. 직접 복구하기

자동 복구가 안되거나 직접 해야 할 때

MyISAM 테이블 직접 복구

방법 1: SQL 명령어로 복구

REPAIR TABLE board_posts;
-- 또는 더 자세히 검사하려면
REPAIR TABLE board_posts EXTENDED;

 

방법 2: 커맨드라인에서 직접

myisamchk -r /var/lib/mysql/mydb/board_posts.MYI
# 또는 더 강력하게
myisamchk -r -o /var/lib/mysql/mydb/board_posts.MYI

InnoDB 테이블 직접 복구

InnoDB는 이렇게 간단하지 않다. 몇 가지 방법

방법 1: mysqldump로 데이터 빼서 다시 넣기

mysqldump -u root -p --single-transaction mydb user_stats > user_stats_backup.sql
mysql -u root -p mydb < user_stats_backup.sql

 

방법 2: ALTER TABLE로 다시 만들기

ALTER TABLE user_stats ENGINE=InnoDB;

 

방법 3: 심각할 때는 강제 복구 모드

# my.cnf에 추가
[mysqld]
innodb_force_recovery=4

숫자는 1-6 사이로 넣을 수 있고, 숫자 클수록 더 강하게 복구한다.

근데 이건 임시로만 쓰고, 데이터 빼내서 백업한 다음에는 꼭 제거해야 된다.

 

6. 실제 상황에서 어떻게 대응했나

한 달 전에 겪었던 상황을 기준으로 대응 방법 공유한다.

사례 1: MyISAM 테이블 충돌

서버 갑자기 다운되고 이런 로그가 뜸

[ERROR] mysqld: Table './mydb/board_posts' is marked as crashed and should be repaired

 

대응 절차

  1. MySQL 서버 재시작 (자동 복구 시도)
  2. 자동 복구 안되면 직접 해결
     
    REPAIR TABLE board_posts;
  3. 잘 됐나 확인
     
    CHECK TABLE board_posts;

사례 2: InnoDB 페이지 손상

대용량 테이블에서 발생한 페이지 깨짐

[ERROR] InnoDB: Database page corruption on disk or a failed file read of tablespace mydb/user_stats page [page id: space=117, page number=2102334]

대응 절차

  1. 우선 테이블 상태 확인 (근데 EXTENDED 옵션은 조심해라, 50GB 테이블에서는 몇 시간 걸릴 수 있음)
     
    CHECK TABLE user_stats;
  2. 테이블 깨졌으면 중요하지 않은 거는 그냥 다시 만들기
     
    ALTER TABLE user_stats ENGINE=InnoDB;
  3. 중요 데이터면 백업에서 복원하거나 innodb_force_recovery 사용해서 데이터 빼내기

그런데 재밌게도, 이번에는 CHECK TABLE 결과가 OK로 나왔다. 몇 가지 가능성이 있다.

  • 일시적인 I/O 에러였을 수도
  • 더블라이트 버퍼가 알아서 복구했을 수도
  • 깨진 페이지가 별로 안 중요한 데이터였을 수도 (인덱스 같은 거)

 

7. 어떤 엔진 쓸까?

고민된다면 참고하자

InnoDB 쓰는 게 좋을 때

  • 진짜 중요한 데이터 (돈 관련, 주문 같은 거)
  • 여러 사람이 동시에 쓰기 하는 경우
  • 외래 키로 데이터 무결성 관리해야 할 때
  • 서버 갑자기 꺼져도 데이터 보존해야 할 때

MyISAM 써도 괜찮을 때

  • 읽기만 많이 하는 경우 (블로그, 정적 컨텐츠)
  • COUNT(*) 같은 거 자주 해야 하는 경우
  • 서버 자원 빡빡한데 읽기 성능 필요할 때
  • 트랜잭션 필요 없는 단순 로그 데이터

근데 특별한 이유 없으면 그냥 InnoDB 쓰는 게 안전하다.

 

8. 자주 물어보는 것들

Q: MyISAM이랑 InnoDB 섞어 써도 돼?

A: 된다. 내 서버도 그렇게 쓰고 있다. 각 테이블 용도에 맞게 선택하면 된다.

 

Q: InnoDB 테이블을 MyISAM으로 바꾸는 방법은?

A: 그냥 이렇게 하면 된다

ALTER TABLE 테이블명 ENGINE=MyISAM;

반대도 똑같이 하면 됨.

 

Q: 테이블 엔진 바꿀 때 주의할 점은?

A: 대용량 테이블은 바꾸는 데 시간 많이 걸리고 서비스에 영향 줄 수 있다. 그리고 엔진 바꾸면 외래 키나 트랜잭션 관련 기능이 달라지니까 그것도 생각해봐야 한다.

 

마무리

MySQL 엔진 선택하고 문제 생겼을 때 대응하는 건 DB 관리의 기본이다.

두 엔진 특성이랑 복구 방법 알면 문제 생겨도 당황 안 하고 해결할 수 있다.

내 경험상 큰 데이터나 중요한 건 InnoDB, 읽기 위주의 간단한 로그 데이터는 MyISAM 쓰는 게 좋다.

그리고 무조건 백업 배겅ㅂ 백업을 백업!!!!!!!!