오류 메시지에 속지 마십시오 The table 'my_table' is full
. 이 드문 시나리오는 디스크 공간과 전혀 관련이 없습니다. 이 테이블 전체 조건은 InnoDB의 내부 배관과 관련이 있습니다.
먼저,이 InnoDB 아키텍처 다이어그램을 살펴보십시오
시스템 테이블 스페이스 (파일 ibdata)에는 롤백 세그먼트 당 128 개의 롤백 세그먼트 와 롤백 세그먼트 당 1023 개의 롤백 슬롯 만 있습니다 . 이로 인해 트랜잭션 롤백 용량의 크기가 제한됩니다. 다시 말해, 단일 롤백 세그먼트가 트랜잭션을 지원하기 위해 1023 개 이상의 슬롯이 필요한 경우 트랜잭션은 해당 table is full
조건에 도달합니다 .
뉴저지에있는 Red Lobster 레스토랑을 생각해보십시오 . 수용 인원은 200 명입니다. 식당이 가득 차면 사람들이 줄을 서서 기다릴 수 있습니다. 줄에있는 사람들이 참을성이 없으면 식당이 가득 차서 떠날 수 있습니다. 분명히 해결책은 뉴저지를 더 크게 만들거나 디스크 공간을 늘리는 것이 아닙니다. 해결책은 Red Lobster 식당을 더 크게 만드는 것입니다. 이렇게하면 좌석 수용 인원을 240 명으로 늘릴 수 있습니다. 그럼에도 불구하고 240 명 이상이 레드 랍스터에 오기로 결정하면 노선이 외부에 형성 될 수 있습니다.
예를 들어, 2TB의 시스템 테이블 스페이스를 가진 클라이언트가 있고 innodb_file_per_table 이 비활성화되었습니다. (ibdata1의 경우 346G, ibdata2의 경우 재설정). 나는이 쿼리를 실행
SELECT SUM(data_length+index+length) InnoDBDataIndexSpace
FROM information_schema.tables WHERE engine='InnoDB';
다음으로, 나는 ibdata1과 ibdata2에 대한 파일 크기의 합에서 InnoDBDataIndexSpace를 뺍니다. 나는 두 가지 충격을 받았다
- 시스템 테이블 스페이스에 106GB가 남아 있습니다.
- 나는이 같은
Table is Full
조건을 얻었다
이는 106GB가 InnoDB의 내부 배관에 사용 중임을 의미합니다. 당시 클라이언트는 ext3을 사용하고있었습니다.
나를위한 해결책은 ibdata3를 추가하는 것이 었습니다. 나는 내 이전 게시물에서 이것을 논의 했다. "innodb_file_per_table"으로 "테이블이 가득 찼다"고 어떻게 해결할 수 있습니까?
나는 이것을 다른 게시물에서도 논의했습니다.
innodb_file_per_table 이 활성화 된 경우에도이 조건이 발생할 수 있습니다 . 어떻게? 롤백 및 실행 취소 로그는 제어되지 않은 스파이크의 소스이며 ibdata1의 증가입니다 .
실제 질문
테이블에 인덱스를 추가하고을 가져 오기 Table is Full
때문에 테이블은 크기가 커서 단일 롤백 세그먼트에 맞지 않아야합니다. 다음을 수행해야합니다.
단계 01
덤프 파일로 데이터 가져 오기
mysqldump --no-create-info mydb mytable > table_data.sql
단계 02
MySQL에 로그인하여 실행
USE mydb
CREATE TABLE mytable_new LIKE mytable;
ALTER TABLE mytable_new ADD INDEX ... ;
ALTER TABLE mytable RENAME mytable_old;
ALTER TABLE mytable_new RENAME mytable;
단계 03
데이터와 함께 추가 색인이있는 테이블을로드하십시오.
mysql -Dmydb < table_data.sql
그게 다야.
문제는 ALTER TABLE이 거대한 테이블의 모든 행을 단일 트랜잭션으로 삽입하려고 시도한다는 것입니다. mysqldump를 사용하면 단일 트랜잭션의 모든 행이 아니라 한 번에 수천 개의 행 (현재 색인으로)에 데이터를 테이블에 삽입합니다.
걱정하지 마십시오 what if this doesn't work?
. 원본 테이블의 이름 mytable_old
은 어떤 경우 에도 지정 됩니다. 백업 역할을 할 수 있습니다. 새 테이블이 적합하다는 것을 알면 백업을 삭제할 수 있습니다.
시도 해봐 !!!
업데이트 2014-06-16 11:13 EDT
더 큰 데이터 덤프가 걱정된다면 gzip으로 압축하십시오.
동일한 단계를 수행 할 수 있지만 다음과 같이 수행하십시오.
단계 01
덤프 파일로 데이터 가져 오기
mysqldump --no-create-info mydb mytable | gzip > table_data.sql.gz
단계 02
MySQL에 로그인하여 실행
USE mydb
CREATE TABLE mytable_new LIKE mytable;
ALTER TABLE mytable_new ADD INDEX ... ;
ALTER TABLE mytable RENAME mytable_old;
ALTER TABLE mytable_new RENAME mytable;
단계 03
데이터와 함께 추가 색인이있는 테이블을로드하십시오.
gzip -d < table_data.sql.gz | mysql -Dmydb
또는
gunzip < table_data.sql.gz | mysql -Dmydb
업데이트 2014-06-16 12:55 EDT
나는이 문제와 관련하여 또 다른 측면을 생각했습니다.
DML이 아닌 DDL을 수행하고 있기 때문에 이것이 InnoDB 내부 배관이 아닐 수 있습니다. 이후 DDL은 InnoDB에 대한 롤백 할 수없는 , 문제는 외부 배관이어야한다. 이 외부 배관이 막히는 곳은 어디입니까? OS의 임시 폴더가 의심됩니다. 왜?
140616 13:04:33 InnoDB: Error: Write to file (merge) failed at offset 3 1940914176.
InnoDB: 1048576 bytes should have been written, only 970752 were written.
InnoDB: Operating system error number 0.
InnoDB: Check that your OS and file system support files of this size.
InnoDB: Check also that the disk is not full or a disk quota exceeded.
InnoDB: Error number 0 means 'Success'.
InnoDB: Some operating system error numbers are described at
InnoDB: http://dev.mysql.com/doc/refman/5.5/en/operating-system-error-codes.html
140616 13:04:33 [ERROR] /usr/libexec/mysqld: The table 'my_table' is full
disk quota exceeded
?를 참조하십시오 . 이 디스크 할당량은 어디에 부과됩니까?
이 쿼리를 실행
SHOW GLOBAL VARIABLES LIKE 'tmpdir';
당신은 말했다 /var/lib/mysqltmp
이제 OS에서 이것을 실행하십시오.
df -h /var/lib/mysqltmp
뭔가 공간 /var/lib/mysqltmp
이 부족 하다는 것을 말해줍니다. 결국, 당신은 14G 만 사용할 수 있습니다. DDL의 관점에서 (인덱스 생성) ibdata1 파일이 아니라 tmpdir
위치 에서 롤백이 발생했습니다 . 경우 /var/lib/mysqltmp
어디서든 장착되어 있지 않은 경우, 임시 데이터는 루트 파티션에 기록되고있다. /var/lib/mysqltmp
어딘가에 마운트 된 경우 해당 마운트는 행 데이터로 채워집니다. 두 경우 모두 DDL을 완료 할 공간이 충분하지 않습니다.
여기에 두 가지 옵션이 있습니다
옵션 1
큰 디스크 (아마도 100GB 이상) /var/lib/mysqltmp
를 만들어 큰 디스크에 마운트 할 수도 있습니다 .
옵션 # 2
디스크 공간이 제한되어 있어도 3 단계 제안이 계속 작동합니다.
해설
당신이 게시 한 오류 메시지가 부끄러운 일입니다.
InnoDB: Operating system error number 0.
InnoDB: Error number 0 means 'Success'.
이것은 OS가 괜찮다는 것을 의미합니다. 또한이 상황과 관련된 오류 번호가 없습니다.
알아야 할 또 다른 것이 있습니다. MySQL 문서에 따르면 InnoDB 용 빠른 인덱스 생성은 여전히 디스크로 이동합니다 .
인덱스 작성 중에 파일은 임시 디렉토리 (UNIX의 경우 $ TMPDIR, Windows의 경우 % TEMP % 또는 --tmpdir 구성 변수의 값)에 기록됩니다. 각 임시 파일은 새 인덱스를 구성하는 하나의 열을 보유 할 수있을만큼 커야하며 각 인덱스는 최종 인덱스에 병합 되 자마자 제거됩니다.
MySQL의 한계로 인해 TEMPORARY TABLE에서 인덱스를 생성 할 때“빠른 인덱스 생성”을 사용하지 않고 테이블이 복사됩니다. 이것은 MySQL Bug # 39833로보고되었습니다 .
업데이트 2014-06-16 13:58 EDT
[mysqld]
datadir = /mnt/cbsvolume1/var/lib/mysql
tmpdir = /mnt/cbsvolume1/var/lib/mysql
/mnt/cbsvolume1/var/lib/mysql
100G 이상 무료 인지 확인하십시오