몇 시간 동안 오프라인으로 전환하지 않고 어떻게 66,862,521 행 테이블을 MyISAM에서 InnoDB로 변환합니까?


18

응용 프로그램을 오프라인으로 만들지 않고도 거대한 MyISAM 테이블을 InnoDB로 변환하는 것이 가능하고 방법입니다. 매 초마다 해당 테이블에 몇 개의 행을 삽입해야하지만 약 2 분 동안 일시 중단 할 수 있습니다.

분명히 ALTER TABLE ... engine = innodb가 작동하지 않습니다. 그래서 나는 innodb 엔진으로 새로운 테이블을 만들고 그 안에 내용을 복사 할 계획을 가지고있었습니다. 마지막으로 응용 프로그램 로그 스레드와 RENAME TABLE을 일시 중단합니다.

불행히도 100 행의 작은 배치로 복사하는 작업도 일정 시간이 지난 후 상당한 지연을 발생시킵니다.

편집 : 기존 행은 변경되지 않으며이 테이블은 로깅에 사용됩니다.



3
그 질문은 대화 시간을 최소화하는 것입니다. 대화에 며칠 또는 몇 주가 걸리더라도 상관 없습니다. 그러나 응용 프로그램의 중단 시간없이 눈에 띄게 지연이 발생하지 않고 백그라운드에서 작동해야합니다.
Hendrik Brummermann

답변:


15

다음과 같이 마스터 마스터 설정을 작성하십시오.

  • 두 번째 마스터 인 MasterB 만들기
  • MasterB는 logTable
  • logTable_newinnodb로 생성
  • INSERT INTO logTable_new SELECT * FROM logTableMasterB에서 복제 (psuedocode)를 실행 하여 MasterA로 복제를 보냅니다.
  • logTable_newMasterA에서 동기화가 완료 되면 테이블을 교체하십시오.

10

다음과 같은 제약 조건이 주어집니다.

대화에 며칠 또는 몇 주가 걸리더라도 상관 없습니다. 그러나 응용 프로그램의 다운 타임을 요구하지 않고 눈에 띄는 지연을 발생시키지 않고 백그라운드에서 작동해야합니다.

로깅을 수행하는 동안 프로세스를 시작한 내용을 알 수 있도록 마커를 설정하는 좋은 방법이 있다면 모든 로그를 다시 적용하거나 텍스트 파일에 로그를 기록 할 수 있습니다. 나중에 함께 섭취 할 수 있습니다 LOAD DATA INFILE

문제의 일부는 더 작은 배치로 쓰는 것은 인덱스를 계속해서 다시 계산해야한다는 것을 의미합니다. 한 번에 모두 실행하는 것이 좋지만 시스템에 약간의 '지각 적'지연이 발생할 수 있습니다. 그러나 프로덕션 서버에서는이를 수행 할 필요가 없습니다.

  1. 나중에이 시점부터 로그를 다시 적용 할 수 있도록 로깅을 일시 중지하거나 마커를 설정하십시오.
  2. MyISM 테이블을 다른 시스템으로 복사
  3. 다른 시스템에서 다른 이름으로 InnoDB 테이블을 생성하고 데이터를 마이그레이션하십시오 (덤프하여 사용하는 것이 더 빠를 수도 있음 LOAD DATA INFILE)
  4. InnoDB 테이블을 원래 시스템으로 다시 복사
  5. 로깅에 대한 다른 마커를 설정하십시오.
  6. 마지막 두 마커 사이에서 새 로그에 모든 로그를 다시 적용하십시오.
  7. (6 단계가 1 분 이상 걸리면 몇 초가 될 때까지 5 단계와 6 단계를 반복하십시오)
  8. 테이블을 교체하십시오 (이전 이름을 table_BACKUP으로 바꾸십시오, 이전 이름으로 새 테이블을 바꾸십시오)
  9. 마지막 마커 이후 로그를 잡습니다.

9

불행히도 100 행의 작은 배치로 복사하는 작업도 일정 시간이 지난 후 상당한 지연을 발생시킵니다.

각 배치 사이에 지연을 추가하거나 업데이트를 배치하고 이전 배치 직후에 각 배치를 실행합니까?

그렇다면 다음과 같이 좋아하는 언어로 변환을 스크립팅하십시오.

repeat
    copy oldest 100 rows that haven't been copied yet to new table
    sleep for as long as that update took
until there are <100 rows unprocessed
stop logging service
move the last few rows
rename tables
restart logging
delete the old table when you are sure the conversion has worked

이렇게하면 시스템 사용이 시간에 따라 달라짐에 따라 부하의 차이를 허용하더라도 변환이 서버 용량의 절반 이상을 차지하지 않도록해야합니다.

데이터베이스 요구는 사용자에 대한 몇 가지 작업을 할 때 서비스가 상대적으로 유휴 상태 일 때 가능한 한 많은 시간을 같이 사용하지만 (잠재적으로 상당한 시간 기간 동안 일시 중지) 전원 백업 할 경우 또는 교체 sleep for as long as the update took와 함께 if the server's load is above <upper measure>, sleep for some seconds then check again, loop around the sleep/check until the load drops below <lower measure>. 즉, 조용한 시간에 미리 스팀을 낼 수 있지만 서버가 정상적인 작업을 수행하는 중일 때는 완전히 일시 중지됩니다. 로드 결정은 Linux에 따라 OS에 따라 달라지며 1 분로드 평균 값 /proc/loadavg또는 출력 결과 와 비슷합니다 uptime. <lower measure>그리고 <upper measure>당신의 프로세스가 바로 다음부터 부하 측정에 영향을 미치는 때문에 자신의 다시 시작하는 일시 보관하지 않도록 차이가이 같은 컨트롤에서 평소 불구하고, 같은 값이 될 수 있습니다.

물론 이것은 오래된 행이 수정 될 수있는 테이블에서는 작동하지 않지만 설명 한 것과 같은 로그 테이블에서는 제대로 작동합니다.

이 경우 새 테이블을 채운 인덱스를 작성하는 일반적인 지혜를 무시하고 싶을 것 입니다. 가능한 한 빨리 (시스템의 나머지 부분에 미치는 영향을 줄이려면) 원할 때 실제로 더 효율적이지만,이 경우 프로세스가 끝날 때 큰 부하를 원하지 않습니다. 인덱스는 한 번에 완전히 생성되므로 작업이 바쁠 때 일시 중지 할 수없는 프로세스입니다.


4

이런 식으로 작동합니까?

  1. 로깅을 일시 중지합니다 (그래서 $auto_increment로깅 테이블의 내용 mytable 은 변경되지 않습니다).
  2. $auto_increment사용 하여 값을 기록하십시오 SHOW TABLE STATUS LIKE 'mytable'.
  3. CREATE TABLE mytable_new LIKE mytable
  4. ALTER TABLE mytable_new AUTO_INCREMENT=$auto_increment ENGINE=Innodb
  5. RENAME TABLE mytable TO mytable_old, mytable_new TO mytable
  6. 로깅을 다시 활성화하십시오. Innodb 테이블이 이제 채우기 시작합니다.
  7. INSERT INTO mytable SELECT * FROM mytable_old.

7 단계는 일반 로깅으로 차단되어서는 안되므로 일괄 처리 또는 한 명령문으로 수행 할 수 있습니다.


innodb가 auto_increment를 처리하는 방식 때문에 여전히 차단됩니다. 기본적으로 innodb는 auto_increment 열에 삽입 할 때 테이블 레벨 잠금을 수행하고 삽입이 완료되는 즉시 잠금을 해제합니다.
ovais.tariq
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.