[mysql] 테이블 잠금없이 거대한 MySQL 프로덕션 테이블에 인덱스 생성

~ 5M 행 MySQL 테이블에 인덱스를 만들어야합니다. 그것은 생산 테이블이며 CREATE INDEX 문을 실행하면 모든 것의 완전한 블록이 두려워 …

삽입 및 선택을 차단하지 않고 해당 인덱스를 만드는 방법이 있습니까?

중지하고 색인을 생성하고 시스템을 다시 시작할 필요가 없는지 궁금합니다!



답변

[2017] 업데이트 : MySQL 5.6은 온라인 인덱스 업데이트를 지원합니다.

https://dev.mysql.com/doc/refman/8.0/en/innodb-online-ddl-operations.html#online-ddl-index-syntax-notes

MySQL 5.6 이상에서는 인덱스가 생성되거나 삭제되는 동안 테이블을 읽기 및 쓰기 작업에 사용할 수 있습니다. CREATE INDEX 또는 DROP INDEX 문은 테이블에 액세스하는 모든 트랜잭션이 완료된 후에 만 ​​완료되므로 인덱스의 초기 상태는 테이블의 가장 최근 내용을 반영합니다. 이전에는 인덱스를 만들거나 삭제하는 동안 테이블을 수정하면 일반적으로 테이블에서 INSERT, UPDATE 또는 DELETE 문을 취소하는 교착 상태가 발생했습니다.

[2015] MySQL 5.5에서 테이블 인덱스 블록 쓰기 업데이트

위의 답변에서 :

“데이터베이스가 온라인 상태 일 때 인덱스가 5.1보다 큰 버전을 사용하는 경우 생성됩니다. 따라서 프로덕션 시스템 사용이 중단되지 않을 것이라고 걱정하지 마십시오.”

이것은 **** FALSE ****입니다 (최소한 MyISAM / InnoDB 테이블의 경우 99.999 %의 사람들이 사용합니다. Clustered Edition은 다릅니다.)

테이블에서 UPDATE 작업을 수행하면 인덱스가 생성되는 동안 BLOCK 됩니다 . MySQL은 이것에 대해 정말, 정말 어리 석습니다.

테스트 스크립트 :

(
  for n in {1..50}; do
    #(time mysql -uroot -e 'select  * from website_development.users where id = 41225\G'>/dev/null) 2>&1 | grep real;
    (time mysql -uroot -e 'update website_development.users set bio="" where id = 41225\G'>/dev/null) 2>&1 | grep real;
  done
) | cat -n &
PID=$!
sleep 0.05
echo "Index Update - START"
mysql -uroot website_development -e 'alter table users add index ddopsonfu (last_name, email, first_name, confirmation_token, current_sign_in_ip);'
echo "Index Update - FINISH"
sleep 0.05
kill $PID
time mysql -uroot website_development -e 'drop index ddopsonfu on users;'

내 서버 (InnoDB) :

Server version: 5.5.25a Source distribution

출력 (인덱스 업데이트를 완료하는 데 걸리는 ~ 400ms 동안 6 번째 작업이 어떻게 차단되는지 확인) :

 1  real    0m0.009s
 2  real    0m0.009s
 3  real    0m0.009s
 4  real    0m0.012s
 5  real    0m0.009s
Index Update - START
Index Update - FINISH
 6  real    0m0.388s
 7  real    0m0.009s
 8  real    0m0.009s
 9  real    0m0.009s
10  real    0m0.009s
11  real    0m0.009s

차단하지 않는 읽기 작업 대 (스크립트에서 줄 주석을 바꿉니다) :

 1  real    0m0.010s
 2  real    0m0.009s
 3  real    0m0.009s
 4  real    0m0.010s
 5  real    0m0.009s
Index Update - START
 6  real    0m0.010s
 7  real    0m0.010s
 8  real    0m0.011s
 9  real    0m0.010s
...
41  real    0m0.009s
42  real    0m0.010s
43  real    0m0.009s
Index Update - FINISH
44  real    0m0.012s
45  real    0m0.009s
46  real    0m0.009s
47  real    0m0.010s
48  real    0m0.009s

다운 타임없이 MySQL의 스키마 업데이트

지금까지 MySql 스키마를 업데이트하고 가용성 중단을 겪지 않는 방법은 하나뿐입니다. 원형 마스터 :

  • 마스터 A에는 MySQL 데이터베이스가 실행 중입니다.
  • 마스터 B를 서비스로 전환하고 마스터 A에서 쓰기를 복제하도록합니다 (B는 A의 슬레이브 임).
  • 마스터 B에서 스키마 업데이트를 수행합니다. 업그레이드 중에 뒤쳐집니다.
  • 마스터 B가 따라 잡도록하십시오. 불변 : 스키마 변경은 다운 버전 스키마에서 복제 된 명령을 처리 할 수 ​​있어야합니다. 인덱싱 변경 사항이 적용됩니다. 일반적으로 단순 열 추가가 적합합니다. 열을 제거 하시겠습니까? 아마 아닐 것입니다.
  • 원자는 (날 믿어, 당신이 할), 당신은 마지막 쓰기가 B에 복제되어 있는지 확인해야 안전하려면 마스터 B로 마스터 A로부터 모든 클라이언트를 교환 하기 전에B는 첫 번째 쓰기를받습니다. 2 개 이상의 마스터에 대한 동시 쓰기를 허용하면 … 깊은 수준에서 MySQL 복제를 더 잘 이해하거나 고통의 세계로 향합니다. 극심한 고통. 마찬가지로 AUTOINCREMENT 열이 있습니까 ??? 당신은 망했다 (한 마스터에 짝수를 사용하고 다른 마스터에 확률을 사용하지 않는 한). “올바른 일을하기 위해”MySQL 복제를 신뢰하지 마십시오. 그것은 똑똑하지 않으며 당신을 구하지 않을 것입니다. 명령 줄에서 이진 트랜잭션 로그를 복사하여 수동으로 재생하는 것보다 약간 덜 안전합니다. 그래도 이전 마스터에서 모든 클라이언트의 연결을 끊고 새 마스터로 전환하는 작업은 몇 초 안에 스키마 업그레이드를 기다리는 것보다 훨씬 빠르게 수행 할 수 있습니다.
  • 이제 마스터 B는 새로운 마스터입니다. 새 스키마가 있습니다. 인생은 좋다. 맥주를 마셔 라. 최악은 끝났습니다.
  • 마스터 A로 프로세스를 반복하여 스키마를 업그레이드하여 1 차 마스터 (현재 마스터 B)가 전원을 잃거나 사용자가 죽는 경우를 대비하여 새로운 보조 마스터가되도록합니다.

스키마를 업데이트하는 쉬운 방법은 그렇지 않습니다. 심각한 생산 환경에서 실행 가능 네, 그렇습니다. 제발, 제발, 쓰기를 차단하지 않고 MySQL 테이블에 인덱스를 추가하는 더 쉬운 방법이 있다면 알려주세요.

인터넷 검색 은 유사한 기술을 설명하는 이 기사로 연결됩니다. 더 좋은 점은 절차의 동일한 시점에서 술을 마시는 것이 좋습니다 (기사를 읽기 전에 제 답변을 썼다는 점에 유의하세요)!

Percona의 pt-online-schema-change

기사 내가 도구에 대해 이야기 위의 링크는 PT-온라인 스키마 변경은 , 그 작품은 다음과 같습니다 :

  • 원본과 동일한 구조로 새 테이블을 만듭니다.
  • 새 테이블에서 스키마를 업데이트합니다.
  • 변경 내용이 복사본과 동기화되도록 원본 테이블에 트리거를 추가합니다.
  • 원본 테이블에서 일괄 적으로 행을 복사합니다.
  • 원래 테이블을 다른 곳으로 옮기고 새 테이블로 교체하십시오.
  • 이전 테이블을 삭제하십시오.

이 도구를 직접 사용해 본 적이 없습니다. YMMV

RDS

저는 현재 Amazon의 RDS를 통해 MySQL을 사용하고 있습니다. MySQL을 마무리하고 관리하는 정말 멋진 서비스로, 버튼 하나로 새로운 읽기 복제본을 추가하고 하드웨어 SKU에서 데이터베이스를 투명하게 업그레이드 할 수 있습니다. 정말 편리합니다. 데이터베이스에 대한 슈퍼 액세스 권한을 얻지 못하므로 복제를 직접 망칠 수 없습니다 (이것이 축복입니까, 저주입니까?). 그러나 읽기 전용 복제본 승격 을 사용하여 읽기 전용 슬레이브에서 스키마를 변경 한 다음 해당 슬레이브를 새 마스터로 승격 할 수 있습니다. 위에서 설명한 것과 똑같은 트릭으로 실행하기가 훨씬 쉽습니다. 그들은 여전히 ​​컷 오버를 돕기 위해 많은 일을하지 않습니다. 앱을 재구성하고 다시 시작해야합니다.


답변

블로그 게시물에서 설명하는 것처럼 InnoDB ALTER TABLE메커니즘은 MySQL 5.6 용으로 완전히 재 설계되었습니다.

(이 주제에 대한 독점적 인 개요를 보려면 MySQL 문서 에서 오후의 읽을 거리를 제공 할 수 있습니다.)

/ 에 대한 잠금 결과 없이 테이블에 인덱스를 추가하려면 다음 명령문 형식을 사용할 수 있습니다.UPDATEINSERT

ALTER TABLE my_table ADD INDEX my_table__idx (my_column), ALGORITHM=INPLACE, LOCK=NONE;


답변

MySQL 5.6 업데이트 (2013 년 2 월) : 이제 InnoDB 테이블을 사용해도 인덱스가 생성되는 동안 읽기 및 쓰기 작업을 수행 할 수 있습니다-http: //dev.mysql.com/doc/refman/5.6/en/innodb-create-index -overview.html

MySQL 5.6 이상에서는 인덱스가 생성되거나 삭제되는 동안 테이블을 읽기 및 쓰기 작업에 사용할 수 있습니다. CREATE INDEX 또는 DROP INDEX 문은 테이블에 액세스하는 모든 트랜잭션이 완료된 후에 만 ​​완료되므로 인덱스의 초기 상태는 테이블의 가장 최근 내용을 반영합니다. 이전에는 인덱스를 만들거나 삭제하는 동안 테이블을 수정하면 일반적으로 테이블에서 INSERT, UPDATE 또는 DELETE 문을 취소하는 교착 상태가 발생했습니다.

과:

MySQL 5.6에서는이 기능이 더욱 일반화되었습니다. 인덱스가 생성되는 동안 테이블을 읽고 쓸 수 있으며, DML 작업을 차단하지 않고 테이블을 복사하지 않고 더 많은 종류의 ALTER TABLE 작업을 수행 할 수 있습니다. 따라서 MySQL 5.6 이상에서는 일반적으로이 기능 세트를 빠른 인덱스 생성이 아닌 온라인 DDL이라고합니다.

에서 http://dev.mysql.com/doc/refman/5.6/en/glossary.html#glos_fast_index_creation


답변

pt-online-schema-change는 마이그레이션으로 인해 사이트가 중단되지 않도록 정말로 원하는 경우 사용할 수있는 방법입니다.

위의 의견에서 썼 듯이 프로덕션에서 pt-online-schema-change에 대한 몇 가지 경험이 있습니다. 2,000 만개 이상의 레코드와 마스터-> 2 개의 읽기 전용 복제 슬레이브로 구성된 기본 테이블이 있습니다. pt-online-schema-change를 사용하여 새 열 추가, 문자 집합 변경, 여러 인덱스 추가에 이르기까지 최소한 수십 번의 마이그레이션을 수행했습니다. 마이그레이션 시간 동안에도 많은 트래픽을 처리하며 문제가 발생하지 않았습니다. 물론 프로덕션에서 실행하기 전에 모든 스크립트를 매우 철저하게 테스트해야합니다.

pt-online-schema-change가 데이터를 한 번만 복사하면되도록 변경 사항을 하나의 스크립트로 일괄 처리하려고했습니다. 그리고 데이터를 잃을 수 있으므로 열 이름을 변경할 때는 매우주의해야합니다. 그러나 색인을 추가하는 것은 괜찮습니다.


답변