테이블에서 MySQL 인덱스 생성 실패


10

업데이트 : tl; dr : 문제는 MySQL이 TMPDIR인덱스를 만들 때를 사용한다는 것 입니다. 그리고 TMPDIR디스크 공간이 부족한 사람이었습니다.

오리지널 Q :

InnoDB 테이블에 색인을 추가하려고하고 있습니다 table is full error. 디스크 공간이 충분하고 MySQL 구성에 테이블 당 파일 = 1이 있습니다. 테이블 데이터는 85GB이며 인덱스는 약 20GB-30GB이며 디스크 공간이 그보다 훨씬 많다고 가정합니다. 또한 ext3을 사용하고 있으므로 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

이 원인은 무엇이며 어떻게 해결할 수 있습니까?

작성 테이블 :

`CREATE TABLE `my_table` (
 `uid_from` bigint(11) NOT NULL,
 `uid_to` bigint(11) NOT NULL,
 `counter` int(11) NOT NULL,
 `updated` date NOT NULL,
 PRIMARY KEY (`uid_to`,`uid_from`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8`

마찬가지로 데이터는 87.4GB이므로 약 1.5B 행이 있다고 추정합니다.

SHOW GLOBAL VARIABLES LIKE 'tmpdir';
Variable_name   Value
tmpdir  /tmp

[root@web ~]# df -h /tmp
Filesystem      Size  Used Avail Use% Mounted on
/dev/xvda1       40G   24G   14G  64% /

1
"InnoDB : OS 및 파일 시스템이이 크기의 파일을 지원하는지 확인하십시오. InnoDB : 디스크가 꽉 차지 않았거나 디스크 할당량이 초과되었는지 확인하십시오." -확인해 봤어? ext2를 사용하고 있습니까? ext3? xfs? 사용자의 할당량을 확인 했습니까?
Philᵀᴹ

@Phil 모두 확인했습니다. ext3을 사용하고 있으며 디스크 공간에 문제가 없다는 것이 거의 긍정적입니다. 직감은 로그가 한계에 도달 한 것과 관련이 있지만 실제로 확인하고 수정하는 방법을 모릅니다.
Noam

"(병합)"파일이 무엇인지 궁금합니다.
akuzminsky

@akuzminsky 흠 나는 모른다. PHPMyAdmin에서 새 인덱스 생성 만 실행했습니다.
Noam

TMPDIR의 경우 +1인데, 이는 서버에서도 문제였습니다.
Chad E.

답변:


8

오류 메시지에 속지 마십시오 The table 'my_table' is full. 이 드문 시나리오는 디스크 공간과 전혀 관련이 없습니다. 이 테이블 전체 조건은 InnoDB의 내부 배관과 관련이 있습니다.

먼저,이 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/mysql100G 이상 무료 인지 확인하십시오


덤프 (85GB 데이터)에서 처음으로 테이블을 작성하는 데 몇 주가 걸렸습니다. 이 모든 것을 다시하는 것 이외의 다른 방법이 있습니까? 테이블을 분할하는 것이 좋습니다?
Noam

인덱스를 추가하기위한 ALTER TABLE이 여전히 모든 것을 단일 트랜잭션으로로드하려고 시도하기 때문에 파티셔닝은 도움이되지 않습니다. 디스크 공간이 아니라 InnoDB 아키텍처와 싸우는 것을 잊지 마십시오. mysqldump는 롤백 가능성이있는 임시 테이블에 전혀 삽입하지 않고 INSERT 당 수천 행을 삽입하기 때문에이 대답이 도움이 될 것입니다.
RolandoMySQLDBA 2016 년

그러나이 테이블을 작성하는 데는 시간이 오래 걸립니다. 롤백 옵션을 비활성화하는 동안 인덱스 생성을 실행하는 방법이 있습니까?
노암

인덱스 생성은 DML이 아닌 DDL입니다. DDL 동작을 변경할 수 없습니다. 이것이 내 게시물이 DML 기술을 사용하는 이유입니다.
RolandoMySQLDBA 2016 년

BTW 테이블에 몇 개의 행이 있습니까 ???
RolandoMySQLDBA 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.