인덱스 열이있는 큰 테이블의 ALTER TABLE


14

VARCHAR (20) 열이있는 큰 테이블이 있으며이를 VARCHAR (50) 열이되도록 수정해야합니다. 일반적으로이 특정 테이블에서 ALTER TABLE (TINYINT 추가)을 수행하는 데는 약 90-120 분이 걸리므로 데이터베이스 사용자에게 영향을주지 않기 위해 토요일이나 일요일 밤에만 수행 할 수 있습니다. 가능하면 그 전에이 수정을하고 싶습니다.

열도 색인화되므로 열 길이를 수정 한 후 색인을 다시 작성해야하기 때문에 ALTER TABLE이 느려질 것이라고 가정합니다.

웹 앱은 MySQL 복제 환경 (26 개의 슬레이브 및 1 개의 마스터)에서 설정됩니다. 한 번의 방법으로 각 슬레이브에서 ALTER TABLE을 수행하고 (사용자에게 미치는 영향을 최소화) 마스터에서 수행하는 방법이 있지만 ALTER TABLE 명령을 슬레이브에 복제하려고 시도하지 않습니까?

그래서 내 질문은 : 사용자를 방해하지 않고이 테이블을 수정하는 가장 좋은 방법은 무엇입니까?

편집 : 테이블은 InnoDB입니다.


tinyint 열을 추가한다는 것은 실제로 기본값으로 열을 추가하는 것을 의미합니까? 거대한 테이블에서 그렇게하는 데 시간이 오래 걸릴 수 있습니다 ..
Marian

답변:


13

조금 모험심이 많으면 ALTER TABLE을 단계별로 수행하여 문제를 해결할 수 있습니다. 변경하려는 테이블을 WorkingTable이라고 가정합니다. 다음과 같이 단계별로 변경을 수행 할 수 있습니다.

#
#  Script 1
#  Alter table structure of a single column of a large table
#
CREATE TABLE WorkingTableNew LIKE WorkingTable;
ALTER TABLE WorkingTableNew MODIFY BigColumn VARCHAR(50);
INSERT INTO WorkingTableNew SELECT * FROM WorkingTable;
ALTER TABLE WorkingTable RENAME WorkingTableOld;
ALTER TABLE WorkingTableNew RENAME WorkingTable;
DROP TABLE WorkingTableOld;

모든 슬레이브에서이 작업을 수행 할 수 있습니다. 마스터는 어떻습니까? 이것이 슬레이브로 복제되는 것을 어떻게 방지합니까? 단순 : SQL을 마스터의 이진 로그로 보내지 마십시오. ALTER TABLE 작업을 수행하기 전에 세션에서 이진 로깅을 종료하십시오.

#
#  Script 2
#  Alter table structure of a single column of a large table
#  while preventing it from replicating to slaves
#
SET SQL_LOG_BIN = 0;
CREATE TABLE WorkingTableNew LIKE WorkingTable;
ALTER TABLE WorkingTableNew MODIFY BigColumn VARCHAR(50);
INSERT INTO WorkingTableNew SELECT SQL_NO_CACHE * FROM WorkingTable;
ALTER TABLE WorkingTable RENAME WorkingTableOld;
ALTER TABLE WorkingTableNew RENAME WorkingTable;
DROP TABLE WorkingTableOld;

하지만 기다려 !!! 이 명령을 처리하는 동안 들어오는 새로운 데이터는 어떻습니까? 작업 시작시 테이블 이름을 바꾸면 트릭이 발생합니다. 그런 점에서 새 데이터를 입력하지 못하도록이 코드를 약간 변경하십시오.

#
#  Script 3
#  Alter table structure of a single column of a large table
#  while preventing it from replicating to slaves
#  and preventing new data from entering into the old table
#
SET SQL_LOG_BIN = 0;
ALTER TABLE WorkingTable RENAME WorkingTableOld;
CREATE TABLE WorkingTableNew LIKE WorkingTableOld;
ALTER TABLE WorkingTableNew MODIFY BigColumn VARCHAR(50);
INSERT INTO WorkingTableNew SELECT SQL_NO_CACHE * FROM WorkingTableOld;
ALTER TABLE WorkingTableNew RENAME WorkingTable;
DROP TABLE WorkingTableOld;
  • 바이너리 로그를 활성화하지 않은 슬레이브에서 스크립트 1을 실행할 수 있습니다.
  • 바이너리 로그가 활성화 된 슬레이브에서 스크립트 2를 실행할 수 있습니다.
  • 스크립트 3은 마스터 또는 다른 곳에서 실행될 수 있습니다

시도 해봐 !!!


2
내가 볼 수있는 한 가지 문제는 테이블에 'auto_increment'필드가 포함되어 있는지입니다. 기본 테스트를 수행 한 후 CREATE TABLE ..을보고 놀랐습니다. LIKE는 auto_increment 값을 새 테이블에 복사하지 않습니다
Derek Downey

1
@ DTest : 좋은 캐치와 좋은 의견 !!!. information_schema.tables 열 AUTO_INCREMENT에서 auto_increment 값을 검색 할 수 있다고 생각합니다. 테이블에 AUTO_INCREMENT 필드가 없으면 information_schema.tables의 AUTO_INCREMENT 열이 NULL이됩니다. 그렇지 않으면 필요한 AUTO_INCREMENT 값이 포함됩니다. NULL이 아닌 값을 추출하고 ALTER TABLE WorkingSet AUTO_INCREMENT = <somenumber>;를 수행하도록 스크립트를 작성할 수 있습니다. 임시 테이블의 이름을 WorkingSet으로 다시 바꾸기 직전에
RolandoMySQLDBA

@RolandoMySQLDBA 수행 할 수있는 다른 작업은 "show create table WorkingTable"문을 복사하여 WorkingTableNew를 만들고 auto_increment 필드의 값을 안전한 숫자만큼 늘려서 열을 varchar (50)로 변경하는 것입니다. ), 단일 명령문에서 이름 바꾸기 "작업 테이블 이름을 WorkingTableOld로 변경, 테이블 이름을 WorkingTableNew로 작업 테이블로 변경"을 모두 수행하십시오. 단일 명령으로 두 이름 바꾸기를 실행하면 삽입이 실패하지 않습니다 (1000 번의 삽입 / 초를 가져 오는 테이블에 대해 테스트 됨). "insert into ... from"명령을 수행 할 수 있습니다
Gautam Somani

4

문서 에서 내 추측 은 길이 제한을 늘리면 varchar열을 추가하는 것과 같은 문제가 발생하지 않는다는 것입니다.

일부 조작의 경우 임시 테이블이 필요하지 않은 내부 ALTER TABLE이 가능합니다.

그러나 이것은 이것에 대한 의견에서 모순되는 것처럼 보입니다. SO 질문 .

편집하다

적어도 5.0에서 길이를 늘리려면 실제로 임시 테이블 (또는 다른 고가의 다른 작업)이 필요하다는 것을 확인할 수 있다고 생각합니다.

테스트 베드 :

create table my_table (id int auto_increment primary key, varchar_val varchar(10));
insert into my_table (varchar_val)
select 'HELLO'
from (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) s1,
     (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) s2,
     (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) s3,
     (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) s4,
     (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) s5,
     (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) s6;

결과:

alter table my_table modify varchar_val varchar(20);
Query OK, 1000000 rows affected (2.91 sec)

alter table my_table add int_val int;
Query OK, 1000000 rows affected (2.86 sec)

varchar 필드 크기를 수정하려면 새 크기를 초과하지 않는지 확인해야합니다. 크기를 늘리려면이 검사를 최적화해야합니다.
BillThor

3

나는 그 이후로 ENGINE=INNODB

외래 키 제약 조건이있는 경우 이전 테이블 (현재 이름이 바))을 가리키는 제약 조건없이 변경하거나 이름을 바꿀 수 없습니다. 나중에 지속 시간 동안 제약 조건을 변경하거나 삭제해야합니다.


샤방 !!! 너무 사실입니다. 이 경우 원래 테이블에서 alter table 만 수행 할 수 있습니다. ALTER TABLE이 발생하기 전에 최소한 제약 조건을 사용하지 않는 게임을해야 할 수도 있습니다. 아주 좋은 캐치 +1!
RolandoMySQLDBA
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.