테이블을 잠그지 않고 ALTER TABLE?


107

MySQL에서 ALTER TABLE 문을 수행 할 때 문이 지속되는 동안 전체 테이블이 읽기 잠금 상태가됩니다 (동시 읽기는 허용되지만 동시 쓰기는 금지됨). 큰 테이블 인 경우 INSERT 또는 UPDATE 문이 looooong 시간 동안 차단 될 수 있습니다. 프로세스 전체에서 테이블을 업데이트 할 수있는 방식으로 열을 추가하는 것과 같이 "핫 변경"을 수행하는 방법이 있습니까?

주로 MySQL 솔루션에 관심이 있지만 MySQL이 할 수없는 경우 다른 RDBMS에 관심이 있습니다.

명확히하기 위해, 제 목적은 추가 테이블 열이 필요한 새로운 기능이 프로덕션으로 푸시 될 때 다운 타임을 방지하는 것입니다. 모든 데이터베이스 스키마 시간이 지남에 따라 변경 됩니다 . 이러한 변경으로 인해 불가피하게 다운 타임이 발생해야한다는 사실을 왜 받아 들여야하는지 모르겠습니다. 그것은 단지 약합니다.


2
테이블을 몇 번 변경할 것인지 궁금하십니까?
Allain Lalonde

1
IMHO, 데이터베이스 스키마 변경은 완전히 새로운 버전과 관련이 있습니다. 다른 변경 사항처럼 산발적으로 롤아웃되지 않습니다. 필연적으로 큰 문제입니다.
dkretz

9
@AllainLalonde-특히 시스템의 다운 타임이 인명이나 많은 비용을들이는 경우이 질문을 합법적으로 만듭니다. 어쨌든 새로운 소프트웨어 요구 사항이 가끔 나타납니다.
Nathan Long

답변:


60

유일한 다른 옵션은 어쨌든 많은 RDBMS 시스템이 수행하는 작업을 수동으로 수행하는 것입니다 ...-
새 테이블 만들기

그런 다음 한 번에 청크에 이전 테이블의 내용을 복사 할 수 있습니다. 항상 소스 테이블의 INSERT / UPDATE / DELETE에주의해야합니다. (트리거에 의해 관리 될 수 있습니다. 이로 인해 속도가 느려지지만 잠금이 아닙니다 ...)

완료되면 소스 테이블의 이름을 변경 한 다음 새 테이블의 이름을 변경하십시오. 가급적 거래에서.

완료되면 해당 테이블을 사용하는 저장 프로 시저 등을 다시 컴파일합니다. 실행 계획은 더 이상 유효하지 않을 것입니다.

편집하다:

이 제한이 약간 열악하다는 의견이 있습니다. 그래서 나는 그것이 왜 그런지 보여주기 위해 그것에 새로운 관점을 넣을 것이라고 생각했습니다.

  • 새 필드를 추가하는 것은 모든 행에서 하나의 필드를 변경하는 것과 같습니다.
  • 필드 잠금은 행 잠금보다 훨씬 어렵고 테이블 잠금은 신경 쓰지 않습니다.

  • 실제로 디스크의 물리적 구조를 변경하고 모든 레코드가 이동합니다.
  • 이것은 전체 테이블에 대한 업데이트와 같지만 더 많은 영향을 미칩니다.

2
그리고 교체하기 전에 철저한 테스트 계획을 세우십시오. 실패하면 다시 시작하십시오.
dkretz

2
트리거를 통해 동기화를 관리하는 것은 좋은 생각이었습니다. 나는 너무 오랫동안 MySQL을 사용해 왔기 때문에 지금 트리거가 있다는 것을 잊었습니다. 저는이 기술을 사용해 왔으며 이제 기능적인 핫 변경 스크립트가 있습니다. 진행률 표시 줄이 있습니다. 그리고 그것은 MyISAM과 함께 작동합니다. 인생은 좋다.
Daniel

2
+1 이것은 말 그대로 UI에서 특정 종류의 테이블을 변경할 때 SQL Enterprise Manager가 백그라운드에서 수행하는 작업입니다. SQL 2008에서는 실제로 경고를 추가하여 사용자가 이러한 과감한 작업을 수행하는 것을 알 수 있습니다.
BradC

2
변경되는 테이블을 참조하는 외래 키에 대해서는 언급하지 않았습니다. 그게 문제가되지 않을까요?
Rafay

2
@MohammadRafayAleem-그리고 AUTOINCREMENT 필드, 뷰, 트리거 등.하지만 그래도 접근 방식 은 여전히 ​​실행 가능합니다.
MatBailie

42

Percona는 이를 수행 할 수있는 pt-online-schema-change 라는 도구를 만듭니다 .

본질적으로 테이블의 복사본을 만들고 새 테이블을 수정합니다. 새 테이블을 원본과 동기화 상태로 유지하기 위해 트리거를 사용하여 업데이트합니다. 이렇게하면 백그라운드에서 새 테이블을 준비하는 동안 원래 테이블에 액세스 할 수 있습니다.

이는 위에서 제안한 Dems 방법과 유사하지만 자동화 된 방식으로 수행됩니다.

그들의 도구 중 일부는 데이터베이스에 연결하는 학습 곡선이 있지만 일단 다운되면 훌륭한 도구입니다.

전의:

pt-online-schema-change --alter "ADD COLUMN c1 INT" D=db,t=numbers_are_friends

링크가 끊어진 것 같습니다. 링크가 작동하는 것으로 나타났습니다 .
Noam Ben Ari

25

이 질문은 2009 년입니다. 이제 MySQL은 다음과 같은 솔루션을 제공합니다.

온라인 DDL (데이터 정의 언어)

DDL (주로 ALTER TABLE) 작업 중에 InnoDB 테이블의 성능, 동시성 및 가용성을 개선하는 기능입니다. 자세한 내용은 14.11 절.“InnoDB 및 온라인 DDL”을 참조하십시오.

세부 사항은 작업 유형에 따라 다릅니다. 경우에 따라 ALTER TABLE이 진행되는 동안 테이블을 동시에 수정할 수 있습니다. 테이블 복사를 수행하지 않거나 특별히 최적화 된 유형의 테이블 복사를 사용하지 않고 작업을 수행 할 수 있습니다. 공간 사용량은 innodb_online_alter_log_max_size 구성 옵션에 의해 제어됩니다.

테이블에 대한 액세스를 완전히 차단할 것인지 (LOCK = EXCLUSIVE 절), DML이 아닌 쿼리를 허용 할 것인지 (LOCK = SHARED 절) 또는 전체 쿼리와 DML을 허용 할 것인지 선택하여 DDL 작업 중 성능과 동시성 간의 균형을 조정할 수 있습니다. 테이블에 대한 액세스 (LOCK = NONE 절). LOCK 절을 생략하거나 LOCK = DEFAULT를 지정하면 MySQL은 작업 유형에 따라 가능한 한 많은 동시성을 허용합니다.

테이블의 새 복사본을 생성하는 대신 가능한 한 제자리에서 변경을 수행하면 테이블 복사 및 보조 인덱스 재구성과 관련된 디스크 공간 사용량 및 I / O 오버 헤드가 일시적으로 증가하지 않습니다.

자세한 내용은 MySQL 5.6 참조 설명서-> InnoDB 및 온라인 DDL 을 참조하십시오.

MariaDB에서도 온라인 DDL을 사용할 수있는 것 같습니다.

또는 ALTER ONLINE TABLE을 사용하여 ALTER TABLE이 동시 작업을 차단하지 않도록 할 수 있습니다 (잠금 없음). LOCK = NONE과 동일합니다.

ALTER TABLE에 대한 MariaDB KB


3
더 이상 현재 버전의 MySQL을 참조하지 않기 때문에 다른 모든 답변을 대부분 무효화한다는 점을 감안할 때 투표 외에 다른 방법이 없다는 것은 부끄러운 일입니다.
Burhan Ali


14

옵션이라면 Postgres를 추천합니다. postgres를 사용하면 기본적으로 다음 절차에 다운 타임이 없습니다.

다른 훌륭한 기능은 대부분의 DDL 문이 트랜잭션 적이므로 SQL 트랜잭션 내에서 전체 마이그레이션을 수행 할 수 있으며 문제가 발생하면 전체가 롤백된다는 것입니다.

나는 이것을 조금 전에 썼는데 , 아마도 그것은 다른 장점에 대해 더 많은 통찰력을 줄 수있을 것입니다.


6
Postgres는 여전히 alter에 배타적 잠금을 생성하여 다른 사람이 해당 테이블에서 읽지 못하도록합니다.
clofresh

5
"본질적으로 다운 타임 없음"에 동의하지 않습니다. clofresh가 말했듯이 ALTER TABLE은 모든 동시 읽기 및 쓰기를 차단하는 테이블에 대한 독점 잠금을 가져옵니다. 내 경험상 활성 테이블의 경우 대부분 잠금을 얻지 못할 것입니다 (ALTER TABLE은 굶어 죽을 것입니다). 그리고 트랜잭션을 사용하면 매우 조심하지 않으면 쉽게 교착 상태에 빠질 수 있습니다. 이 때문에 Postgres에서 기존 테이블을 변경할 때 항상 다운 타임을 설정합니다.
Pankrat

1
더 자세한 설명 : dba.stackexchange.com/questions/27153/… 배타적 잠금의 의미와이를 해결하는 몇 가지 방법을 언급합니다
John Douthat

4
예, postgres에서 테이블을 변경하면 배타적 잠금이 발생하지만 작업 자체가 밀리 초 단위로 완료되기 때문에 대부분의 경우 거의 관련이 없습니다. 개인적으로 업무 일 중간에 1 억 개의 행 테이블에 열을 추가하여 다운 타임을 발생시키지 않았습니다.
노아 예터

2
@cobbzilla 예, DROP COLUMN도 빠릅니다. 기본적으로하는 것은 열을 숨김으로 표시하는 것입니다. 삭제되기 전에 해당 열에 있던 값은 여전히 ​​데이터 파일에 있으며 (그리고 다른 트랜잭션에 표시됨) VACUUM FULL을 수행하지 않는 한 그대로 유지됩니다.
Noah Yetter

7

다른 데이터베이스에 대해 질문 했으므로 다음은 Oracle에 대한 몇 가지 정보입니다.

Oracle 테이블에 NULL 열을 추가하는 것은 데이터 사전 만 업데이트하므로 매우 빠른 작업입니다. 이것은 매우 짧은 시간 동안 테이블에 대한 독점 잠금을 보유합니다. 그러나 중복 저장 프로 시저, 뷰, 트리거 등을 무효화합니다. 이러한 항목은 자동으로 다시 컴파일됩니다.

필요한 경우 여기에서 ONLINE 절을 사용하여 색인을 만들 수 있습니다. 다시 말하지만, 매우 짧은 데이터 사전 잠금 만 있습니다. 인덱싱 할 항목을 찾기 위해 전체 테이블을 읽지 만이 작업을 수행하는 동안 아무도 차단하지 않습니다.

외래 키를 추가해야하는 경우이 작업을 수행하고 Oracle이 데이터가 정확하다는 것을 신뢰하도록 할 수 있습니다. 그렇지 않으면 전체 테이블을 읽고 느릴 수있는 모든 값의 유효성을 검사해야합니다 (먼저 인덱스 생성).

새 열의 모든 행에 기본값 또는 계산 된 값을 입력해야하는 경우 대규모 업데이트를 실행하거나 새 데이터를 채우는 작은 유틸리티 프로그램을 실행해야합니다. 특히 행이 많이 커지고 더 이상 블록에 맞지 않는 경우 속도가 느려질 수 있습니다. 이 과정에서 잠금을 관리 할 수 ​​있습니다. 여전히 실행중인 애플리케이션의 이전 버전은이 열에 대해 알지 못하므로 교활한 트리거가 필요하거나 기본값을 지정해야 할 수 있습니다.

여기에서 애플리케이션 서버에서 새 버전의 코드로 전환 할 수 있으며 계속 실행됩니다. 은밀한 방아쇠를 버려라.

또는 이러한 작업을 수행하도록 설계된 블랙 박스 인 DBMS_REDEFINITION을 사용할 수 있습니다.

이 모든 것은 테스트하기가 너무 까다롭기 때문에 주 버전을 출시 할 때마다 일요일 이른 아침 중단이 발생합니다.


3

애플리케이션 업데이트를 수행 할 때 데이터베이스 가동 중지 시간을 감당할 수없는 경우 고 가용성을 위해 2 노드 클러스터를 유지하는 것을 고려해야합니다. 간단한 복제 설정으로 다음과 같이 거의 완전한 온라인 구조 변경을 수행 할 수 있습니다.

  • 모든 변경 사항이 수동 슬레이브에 복제 될 때까지 기다립니다.
  • 수동 슬레이브를 활성 마스터로 변경
  • 이전 마스터에 구조 변경을 수행
  • 새 마스터에서 이전 마스터로 변경 사항을 다시 복제
  • 마스터 스와핑을 다시 수행하고 새 앱 배포를 동시에 수행

항상 쉬운 것은 아니지만 일반적으로 작동 중지 시간이 0입니다! 두 번째 노드는 수동 노드 일 필요는 없으며 테스트, 통계 수행 또는 대체 노드로 사용할 수 있습니다. 인프라가없는 경우 단일 머신 (MySQL 인스턴스 2 개 포함) 내에서 복제를 설정할 수 있습니다.


1
이전 마스터가 클러스터 외부에 있습니까? 아니면 클러스터 내에 있습니까?
John Chornelius

2

아니. MyISAM 테이블을 사용하는 경우 가장 잘 이해하기 위해 테이블 ​​잠금 만 수행합니다. 레코드 잠금은 없으며 단순성을 통해 모든 것을 초고속으로 유지하려고합니다. (다른 MySQL 테이블은 다르게 작동합니다.) 어떤 경우에도 테이블을 다른 테이블에 복사하고 변경 한 다음 전환하여 차이점을 업데이트 할 수 있습니다.

이것은 DBMS가 그것을 지원할 것 같지 않을 정도로 엄청난 변경입니다. 처음에는 테이블의 데이터로이를 수행 할 수있는 이점으로 간주됩니다.



네, MySQL은 일탈입니다. 이것이 내가 "표준"테이블에 대해 구체적으로 지정한 이유입니다.
dkretz

당신은 썼습니다-표준 MySQL 테이블은 테이블 잠금 만 수행합니다-이것은 올바르지 않습니다.
Eran Galperin

인용 한 페이지에서 MyISAM (즉, MySQL 표준) 테이블에 대해 이것을 어떻게 해석합니까? "MySQL은 MyISAM 및 MEMORY 테이블에 대한 테이블 수준 잠금, BDB 테이블에 대한 페이지 수준 잠금, InnoDB 테이블에 대한 행 수준 잠금을 사용합니다."
dkretz

일부 스토리지 엔진은 행 수준 잠금을 사용하고 일부는 테이블 수준 잠금을 사용합니다. 표준 스토리지 엔진이 없습니다 (아마도 phpMyAdmin의 기본값을 의미 할 수 있습니다 ...)
Eran Galperin

2

임시 해결책 ...

다른 해결책은 새 열과 함께 원래 테이블의 기본 키가있는 다른 테이블을 추가하는 것입니다.

기본 키를 새 테이블에 채우고 새 테이블의 새 열에 대한 값을 채운 다음 쿼리를 수정하여 선택 작업을 위해이 테이블을 조인하고이 열 값에 대해 별도로 삽입하고 업데이트해야합니다.

다운 타임이 발생하면 원래 테이블을 변경하고 DML 쿼리를 수정하고 이전에 생성 한 새 테이블을 삭제할 수 있습니다.

그렇지 않으면 percona의 클러스터링 방법, 복제, pt-online-schema 도구를 사용할 수 있습니다.


1

Innodb 플러그인을 사용하면 보조 인덱스 만 추가하거나 삭제하는 ALTER TABLE 문을 "빠르게", 즉 테이블을 다시 빌드하지 않고도 수행 할 수 있습니다.

그러나 일반적으로 MySQL에서 ALTER TABLE은 전체 테이블을 재 구축하는 작업을 포함하며 이는 매우 오랜 시간이 걸릴 수 있습니다 (즉, 테이블에 유용한 양의 데이터가있는 경우).

ALTER TABLE 문을 정기적으로 수행 할 필요가 없도록 애플리케이션을 설계해야합니다. 기다릴 준비가되어 있지 않거나 작은 테이블을 변경하지 않는 한 애플리케이션이 정상적으로 실행되는 동안 ALTER TABLE이 수행되는 것을 원하지 않습니다.


1

두 가지 접근 방식 중 하나를 권장합니다.

  1. 잠재적 인 변경 사항을 염두에두고 데이터베이스 테이블을 디자인하십시오. 예를 들어, 콘텐츠의 데이터 필드를 정기적으로 변경하는 콘텐츠 관리 시스템과 함께 일했습니다. 초기 CMS 필드 요구 사항에 맞게 물리적 데이터베이스 구조를 구축하는 대신 유연한 구조로 구축하는 것이 훨씬 좋습니다. 이 경우 blob 텍스트 필드 (예 : varchar (max))를 사용하여 유연한 XML 데이터를 보유합니다. 이것은 구조적 변경을 매우 덜 빈번하게 만듭니다. 구조적 변경은 비용이 많이들 수 있으므로 여기에서도 비용이 발생하는 이점이 있습니다.

  2. 시스템 유지 보수 시간이 있습니다. 변경 중 (매월 등) 시스템이 오프라인 상태가되고 하루 중 트래픽이 가장 적은 시간 (예 : 오전 3 ~ 5시)에 변경이 예약됩니다. 변경 사항은 프로덕션 롤아웃 전에 단계적으로 진행되므로 가동 중지 시간에 대한 고정 된 예상 시간을 확보 할 수 있습니다.

2a. 중복 서버가 있으므로 시스템이 다운 타임 될 때 전체 사이트가 다운되지 않습니다. 이렇게하면 전체 사이트를 중단하지 않고도 엇갈린 방식으로 업데이트를 "롤"할 수 있습니다.

옵션 2 및 2a는 실행 가능하지 않을 수 있습니다. 더 큰 사이트 / 운영에만 사용되는 경향이 있습니다. 그러나 유효한 옵션이며 여기에 제시된 모든 옵션을 개인적으로 사용했습니다.


1

누군가가 여전히 이것을 읽고 있거나 여기에 오면 mongodb와 같은 NoSQL 데이터베이스 시스템을 사용하는 것이 큰 이점입니다. 수백만 개의 행과 높은 쓰기가있는 큰 테이블에 추가 기능을위한 열이나 인덱스를 추가하도록 테이블을 변경하는 것과 동일한 문제가있었습니다. 매우 오랜 시간 동안 잠금 상태가되어 라이브 데이터베이스에서이 작업을 수행하면 사용자가 실망 할 것입니다. 작은 테이블에서 벗어날 수 있습니다.

나는 우리가 "테이블을 변경하지 않도록 테이블을 디자인"해야한다는 사실이 싫다. 나는 그것이 오늘날의 웹 사이트 세계에서 작동하지 않는다고 생각합니다. 사람들이 소프트웨어를 어떻게 사용할지 예측할 수 없기 때문에 사용자 피드백을 기반으로 빠르게 변화합니다. mongodb를 사용하면 다운 타임없이 마음대로 "열"을 추가 할 수 있습니다. 실제로 추가하지 않고 새 열로 데이터를 삽입하기 만하면 자동으로 수행됩니다.

체크 아웃 할 가치가있는 곳 : www.mongodb.com


2
MySQL은 여전히 ​​많은 시스템에서 사용되기 때문에 저는 열렬한 NoSQL 지지자 임에도 불구하고 SQL RDBMS에서 스키마 변경을 달성하는 방법에 대한 질문입니다.
Alexy

1

일반적으로 대답은 "아니오"입니다. 잠재적으로 많은 업데이트가 필요한 테이블의 구조를 변경하고 있습니다. "라고 동의합니다.이 작업을 자주 수행 할 것으로 예상되면"더미 "열에 대한 대안을 제공 할 것입니다. VIEW대신 s를 사용하십시오. 테이블의 SELECT데이터를 보내고. IIRC, 뷰의 정의를 변경하는 것은 상대적으로 가볍고 쿼리 계획이 컴파일 될 때 뷰를 통해 간접 수행됩니다. 경비는 새 테이블에 열을 추가하고 만들어야 할 것입니다 JOIN열에서 볼 수 있습니다 .

물론 이것은 외래 키를 사용하여 계단식 삭제 및 기타 작업을 수행 할 수있는 경우에만 작동합니다. 다른 보너스는 데이터 조합이 포함 된 새 테이블을 만들고 클라이언트 사용을 방해하지 않고 뷰를 가리킬 수 있다는 것입니다.

그냥 생각.


1

이와 관련하여 Postgres와 MySQL의 차이점은 Postgres에서는 테이블을 다시 생성하지 않고 Oracle과 유사한 데이터 사전을 수정한다는 것입니다. 따라서 작업이 빠르지 만 다른 사용자가 위에서 언급 한 것처럼 매우 짧은 시간 동안 독점 DDL 테이블 잠금을 할당해야합니다.

MySQL에서 작업은 트랜잭션을 차단하면서 새 테이블에 데이터를 복사합니다. 이는 v. 5.6 이전의 MySQL DBA에게 주된 고통이었습니다.

좋은 소식은 MySQL 5.6 릴리스 이후 대부분 의 제한이 해제 되었으며 이제 MYSQL DB의 진정한 힘을 즐길 수 있다는 것입니다.


3
MySql 5.6의 변경 사항에 대한 참조에 연결하려고했지만 작동하지 않았습니다. 다시 시도하십시오.
dg99

1

SeanDowney가 언급했듯이 pt-online-schema-change는 여기 질문에서 설명한 작업을 수행 할 수있는 최고의 도구 중 하나입니다. 나는 최근에 라이브 DB에서 많은 스키마 변경을 수행했으며 꽤 잘 진행되었습니다. 내 블로그 게시물 ( http://mrafayaleem.com/2016/02/08/live-mysql-schema-changes-with-percona/) 에서 자세한 내용을 읽을 수 있습니다 .



0

더미 열은 유형을 예측하고 null을 허용 할 수있는 경우 좋은 생각입니다. 스토리지 엔진이 널을 처리하는 방법을 확인하십시오.

MyISAM은 공항에서 전화로 테이블 이름을 언급하더라도 모든 것을 잠급니다. 그냥 그렇게 ...

즉, 잠금 장치는 그렇게 큰 문제가 아닙니다. 새 열에 대한 기본값을 모든 행에 추가하지 않고 null로 유지하고 스토리지 엔진이 쓰기 작업을하지 않을만큼 똑똑한 한, 잠금 상태는 괜찮을 것입니다. 메타 데이터를 업데이트하기에 충분히 오래 유지됩니다. 새로운 값을 쓰려고하면 건배입니다.


1
InnoDB 테이블에 NULL 열을 추가하려고했는데 전체 테이블을 다시 작성해야했습니다. 단순한 "메타 데이터 업데이트"작업이 아닙니다.
Daniel

디자인 할 때 데이터베이스에 추가의 nullable 열을 포함하여 새 기능이 필요한 경우 단순히 사용을 시작하여 새 열을 "추가"할 수 있도록하는 것이 아이디어라고 생각합니다. 좋은 이름은 없지만 데이터 유형이 올바르게 선택 / 예측되면 작동합니다.
supercat 2011 년

0

TokuDB는 열을 추가 / 삭제하고 인덱스 "핫"을 추가 할 수 있습니다.이 테이블은 프로세스 전체에서 완전히 사용할 수 있습니다. www.tokutek.com을 통해 제공됩니다.


-6

별로.

결국 테이블의 기본 구조를 변경하고 있으며 이는 기본 시스템에 매우 중요한 정보입니다. 또한 디스크에서 많은 데이터를 이동하고 있습니다.

이 작업을 많이 할 계획이라면 나중에 사용할 수있는 "더미"열로 테이블을 채우는 것이 좋습니다.


3
더미 열로 테이블을 채우는 것은 정말 나쁜 생각 인 것 같습니다.
Jost
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.