"Mysql Row size too large"에 대한 제한 변경


104

한도를 어떻게 변경할 수 있습니까?

행 크기가 너무 큽니다 (> 8126). 일부 열을 TEXT 또는 BLOB로 변경하거나 사용하면 ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED도움이 될 수 있습니다. 현재 행 형식에서는 BLOB접두사 768 바이트가 인라인으로 저장됩니다.

표:

id  int(11) No       
name    text    No       
date    date    No       
time    time    No       
schedule    int(11) No       
category    int(11) No       
top_a   varchar(255)    No       
top_b   varchar(255)    No       
top_c   varchar(255)    No       
top_d   varchar(255)    No       
top_e   varchar(255)    No       
top_f   varchar(255)    No       
top_g   varchar(255)    No       
top_h   varchar(255)    No       
top_i   varchar(255)    No       
top_j   varchar(255)    No       
top_title_a varchar(255)    No       
top_title_b varchar(255)    No       
top_title_c varchar(255)    No       
top_title_d varchar(255)    No       
top_title_e varchar(255)    No       
top_title_f varchar(255)    No       
top_title_g varchar(255)    No       
top_title_h varchar(255)    No       
top_title_i varchar(255)    No       
top_title_j varchar(255)    No       
top_desc_a  text    No       
top_desc_b  text    No       
top_desc_c  text    No       
top_desc_d  text    No       
top_desc_e  text    No       
top_desc_f  text    No       
top_desc_g  text    No       
top_desc_h  text    No       
top_desc_i  text    No       
top_desc_j  text    No       
status  int(11) No       
admin_id    int(11) No 

1
무엇이 No표시됩니까?
hjpotter92 2010 년

'행 크기가 너무 큼 (> 8126). 일부 열을 TEXT 또는 BLOB로 변경하거나 ROW_FORMAT = DYNAMIC 또는 ROW_FORMAT = COMPRESSED를 사용하면 도움이 될 수 있습니다. 현재 행 형식에서 BLOB 접두사 768 바이트는 인라인으로 저장됩니다.'라는 오류를 업데이트 할 수 없습니다.
Lasha Kurt 2013

적어도 댓글로 게시물에 다른 세부 정보를 추가 할 수 있습니까?
Eineki 2013 년

1
이 데이터가 다른 테이블에있는 경우 대신 외래 키를 사용하는 것이 좋습니다. 이렇게하면 행 크기가 크게 줄어들고 데이터베이스 스키마가 정규화됩니다.
didierc 2013 년

1
@AL : 죄송합니다. 맞습니다. 다른 투표에 근접 투표를하세요
pathikrit 2015

답변:


120

질문은 serverfault 에서도 요청되었습니다 .

MySQL 행 크기에 대해 많이 설명하는 이 기사 를 살펴볼 수 있습니다 . TEXT 또는 BLOB 필드를 사용하더라도 페이지의 각 필드에 대해 처음 768 바이트를 인라인으로 저장하기 때문에 행 크기가 여전히 8K (InnoDB 제한)를 초과 할 수 있습니다.

이 문제를 해결하는 가장 간단한 방법은 InnoDB 에서 Barracuda 파일 형식 을 사용하는 것 입니다. 이것은 기본적으로 처음 768 바이트를 저장하는 대신 텍스트 데이터에 대한 20 바이트 포인터 만 저장함으로써 문제를 완전히 제거합니다.


OP를 위해 일한 방법은 다음과 같습니다.

  1. 섹션 my.cnf아래 의 파일에 다음을 추가 [mysqld]하십시오.

    innodb_file_per_table=1
    innodb_file_format = Barracuda
  2. ALTER사용할 테이블 ROW_FORMAT=COMPRESSED.

    ALTER TABLE nombre_tabla
        ENGINE=InnoDB
        ROW_FORMAT=COMPRESSED 
        KEY_BLOCK_SIZE=8;

위의 방법으로 문제가 해결되지 않을 가능성이 있습니다. InnoDB 엔진 의 알려진 (및 검증 된) 버그 이며 현재 임시 수정 사항은 임시 저장소 로 MyISAM 엔진으로 대체하는 것 입니다. 따라서 파일에서 :my.cnf

internal_tmp_disk_storage_engine=MyISAM

12
+1-> innodb_file_per_table 부분은 중요하며 형식을 Barracuda로 변경하는 것과 관련이 있습니다. 이것이 없으면 MySQL은 자동으로 Antelope를 계속 사용합니다.
Nick

1
@Eduardo 먼저 데이터를 백업하는 것이 좋습니다. 그러나 예, 프로덕션에서도이 작업을 수행 할 수 있습니다!
hjpotter92

3
innodb_file_per_table=1이 옵션을 활성화하는 데 사용 합니다.
Stijn Geukens

2
이것은 문제 해결을 보장하지 않습니다. 이러한 설정을 추가하지만 여전히 오류를 재현 할 수있는 예제 스크립트는 이 게시물 을 참조하십시오 .
Cerin

1
@ user1183352 위의 답장을 업데이트했습니다. 이 문제에 대해 자세히 알아 보도록 다시 상기시켜 주셔서 감사합니다. :)
hjpotter92

61

최근에이 문제에 부딪혀 다른 방식으로 해결했습니다. MySQL 버전 5.6.20을 실행중인 경우 시스템에 알려진 버그가 있습니다. MySQL 문서 보기

중요 버그 # 69477로 인해 외부에 저장된 대규모 BLOB 필드에 대한 리두 로그 쓰기가 가장 최근 체크 포인트를 덮어 쓸 수 있습니다. 이 버그를 해결하기 위해 MySQL 5.6.20에 도입 된 패치는 리두 로그 BLOB 쓰기 크기를 리두 로그 파일 크기의 10 %로 제한합니다. 이 제한의 결과로 innodb_log_file_size는 테이블 행에서 발견 된 가장 큰 BLOB 데이터 크기에 다른 가변 길이 필드 (VARCHAR, VARBINARY 및 TEXT 유형 필드)의 길이를 더한 10 배보다 큰 값으로 설정해야합니다.

제 상황에서 문제가되는 blob 테이블은 약 16MB였습니다. 따라서 내가 해결 한 방법은 my.cnf에 해당 금액의 10 배 이상을 확보 한 다음 일부를 추가하는 것입니다.

innodb_log_file_size = 256M


에 딱 맞다. 매개 변수를 longblob늘리 자마자 필드의 "행 크기가 너무 큼"오류가 사라졌습니다 innodb_log_file_size. 또한 5.6.20을 실행했습니다.
adamup 2014 년

감사. homebrew 5.6.21을 실행하고 있었으며 매개 변수를 변경하면 문제가 해결되었습니다.
nanoman 2014

나를 위해이 오류를 수정하려면 이것과 @ hjpotter92의 대답이 필요했습니다.
Cerin 2015 년

감사. 5.6.21을 실행 중이었고이 솔루션이 도움이되었습니다.
petiar

이것은 내 문제도 해결하지 못했습니다. 비슷한 스레드에서 본 것처럼 많은 VARCHAR 필드를 TEXT로 바꾸는 것을 고려하고 있습니다.
PDoria

28

my.cnf 파일에 다음을 설정하고 mysql 서버를 다시 시작합니다.

innodb_strict_mode=0

2
innodb_strict_mode=0-> 공백이 없습니다. 그렇지 않으면 mariaDB 10.2를 다시 시작하면 오류가 발생합니다.
-P

MySQL의 경우 공백을 제거 할 필요가 없으므로 mariadb로 시도하지 않았습니다.
Karl

1
따라서 문서에 따르면 엄격 모드를 비활성화하면 오류 및 경고가 표시되지 않을 뿐이므로 문제가 해결되지 않는 것 같습니다! download.nust.na/pub6/mysql/doc/innodb-plugin/1.1/en/…
João Teixeira

2
이것은 작동하는 것 같고 문제없이 테이블을 생성하고 데이터를 저장할 수있게합니다
Chris Muench

@ João, 더 많은 작업을 수행합니다 .. dev.mysql.com/doc/refman/8.0/en/…
Karl

24

ENGINE을 전환하고 InnoDB 대신 MyISAM을 사용할 수 있다면 도움이 될 것입니다.

ENGINE=MyISAM

MyISAM에는 두 가지주의 사항이 있습니다.

  1. 거래를 사용할 수 없습니다.
  2. 외래 키 제약 조건을 사용할 수 없습니다.

5
트랜잭션 및 외래 키 제약없이 진행해도 괜찮습니다. 그러나 MyISAM으로 전환 할 때 이러한 정보를 잃어 버리는 것에 유의하십시오.
wobbily_col

이 조언은 제정신이 아닙니다. 트랜잭션과 foregith 키 제약은이 형식의 문제 중 가장 적습니다!
Hassan Syed

이 답변에 반대 투표를해서 죄송합니다. 관련된 모든주의 사항을 언급하도록 업데이트하십시오. 이 조언을 따르는 사람은 내가 어떤 프로덕션 시스템에서도 사용하지 않는 형식으로 전환합니다.
Remco Wendt

2
그리고 MyISAM은 사라집니다.
릭 제임스

2
나를 위해 일했습니다. 제 경우에는 각각 길이가 약 10 개가 넘는 300 개 이상의 필드가있었습니다. 이 표에는 관계가 없으므로 MyISAM으로 전환하는 것이 수정되었습니다.
Robert Saylor 2019-02-28

12

멋진 답변을 공유하고 싶습니다. 도움이 될 수 있습니다. 크레딧 Bill Karwin은 여기를 참조하십시오 /dba/6598/innodb-create-table-error-row-size-too-large

InnoDB 파일 형식에 따라 다르며 현재 Antelope와 Barracuda라는 두 가지 형식이 있습니다.

중앙 테이블 스페이스 파일 (ibdata1)은 항상 Antelope 형식입니다. 테이블 당 파일을 사용하는 경우 my.cnf에서 innodb_file_format = Barracuda를 설정하여 개별 파일이 Barracuda 형식을 사용하도록 할 수 있습니다.

기본 포인트 :

  1. InnoDB 데이터의 16KB 페이지 하나는 최소한 두 행의 데이터를 보유해야합니다. 또한 각 페이지에는 페이지 체크섬 및 로그 시퀀스 번호 등을 포함하는 머리글과 바닥 글이 있습니다. 여기에서 행당 8KB 미만의 제한을 얻을 수 있습니다.

  2. INTEGER, DATE, FLOAT, CHAR와 같은 고정 크기 데이터 유형은이 기본 데이터 페이지에 저장되며 행 크기 제한에 포함됩니다.

  3. VARCHAR, TEXT, BLOB와 같은 가변 크기 데이터 유형은 오버플로 페이지에 저장되므로 행 크기 제한에 완전히 포함되지 않습니다. Antelope에서는 이러한 열의 최대 768 바이트가 오버플로 페이지에 저장 될뿐만 아니라 기본 데이터 페이지에 저장됩니다. Barracuda는 동적 행 형식을 지원하므로 기본 데이터 페이지에 20 바이트 포인터 만 저장할 수 있습니다.

  4. 가변 크기 데이터 유형에는 길이를 인코딩하기 위해 1 바이트 이상의 접 두부가 붙습니다. InnoDB 행 형식에는 필드 오프셋 배열도 있습니다. 그래서 그들의 위키에 문서화 된 내부 구조가 있습니다.

Barracuda는 또한 ROW_FORMAT = COMPRESSED를 지원하여 오버플로 데이터에 대한 추가 스토리지 효율성을 얻습니다.

또한 잘 디자인 된 테이블이 행 크기 제한을 초과하는 것을 본 적이 없다는 점도 언급해야합니다. First Normal Form의 반복 그룹 조건을 위반하는 것은 강력한 "코드 냄새"입니다.


7

나는 같은 문제가 있었고 이것이 나를 위해 해결되었습니다.

ALTER TABLE `my_table` ROW_FORMAT=DYNAMIC;

MYSQL 문서에서 :

DYNAMIC 행 형식은 적합한 경우 인덱스 노드에 전체 행을 저장하는 효율성을 유지하지만 (COMPACT 및 REDUNDANT 형식과 마찬가지로)이 새로운 형식은 B- 트리 노드를 많은 수의 데이터 바이트로 채우는 문제를 방지합니다. 긴 열. DYNAMIC 형식은 긴 데이터 값의 일부가 페이지 외부에 저장되는 경우 일반적으로 모든 값을 페이지 외부에 저장하는 것이 가장 효율적이라는 아이디어를 기반으로합니다. DYNAMIC 형식을 사용하면 더 짧은 열이 B- 트리 노드에 남아있어 주어진 행에 필요한 오버플로 페이지 수를 최소화 할 수 있습니다.


...하지만 다른 파일 형식이 필요하므로 이미 Barracuda를 사용하고 있습니까? 나는 그 명령을 시도하고 오류가 발생하는 원인 말하는Warnings from last query: InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_format > Antelope
테드

HeidiSQL이 내장 GUI를 통해 동일한 명령을 실행하도록했을 때 어떻게 든 성공했지만 전혀 도움이되지 않았고 동일한 오류가 발생했습니다.Row size too large (>8126)
Ted

my.ini에서 innodb_file_format = Barracuda를 설정하고 ALTER TABLE my_tableROW_FORMAT = DYNAMIC; 다시
multimediaxp

네, 결국 제가 실제로 한 일이라고 생각합니다. 그리고 그것이 해결되었다고 생각합니다. 그러나 필사적으로 많은 열을 동시에 TEXT로 변경했습니다. =) Thx 그래도 실제로 그랬다고 생각합니다.
Ted

좋습니다! 이것이 좋은 답변이라고 생각되면 찬성 투표를하고 유효한 답변으로 수락하세요. 감사합니다!
multimediaxp

5

몇 시간을 보낸 후 해결책을 찾았습니다. MySQL 관리자에서 다음 SQL을 실행하여 테이블을 MyISAM으로 변환하십시오.

USE db_name;
ALTER TABLE table_name ENGINE=MYISAM;

create table 문에서 문제가 발생하는 경우별로 도움이되지 않습니다.
Mark Fraser

create table같은 옵션이 있습니다 :CREATE TABLE ... ENGINE=MyISAM ...
xebeche

3

다른 서버에서 백업 된 mysql 데이터베이스를 복원하려고 할 때이 문제가 발생했습니다. 이 문제를 해결 한 것은 my.conf에 특정 설정을 추가하고 (위의 질문에서와 같이) SQL 백업 파일을 추가로 변경하는 것입니다.

1 단계 : my.conf에서 다음 줄을 추가하거나 편집합니다.

innodb_page_size=32K
innodb_file_format=Barracuda
innodb_file_per_table=1

2 단계 :이 오류를 일으키는 테이블에 대한 SQL 백업 파일의 테이블 작성 문에 ROW_FORMAT = DYNAMIC을 추가합니다.

DROP TABLE IF EXISTS `problematic_table`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `problematic_table` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
  ...
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 ROW_FORMAT=DYNAMIC;

위의 중요한 변경 사항은 ROW_FORMAT = DYNAMIC입니다. (원래 SQL 백업 파일에 포함되지 않음)

이 문제를 해결하는 데 도움이 된 소스 : MariaDB 및 InnoDB MySQL 행 크기가 너무 큽니다.


1
1 단계에 설명 된 줄에는 공백이 없어야합니다. innodb_page_size=32K제 경우에는 MariaDB 10.2를 다시 시작하는 오류가 발생했기 때문에 Line 이 작동하지 않았습니다. 대신, 추가 innodb_strict_mode=0설명 된대로 선을 여기에
Pathros

1
Pathros 피드백에 감사드립니다. 제 답변을 업데이트하고 1 단계에서 공백을 제거했습니다.
matyas

MySQL <= 5.7.5 참고 사항 : 32K는 innodb_page_size에 유효한 옵션이 아닙니다. 참조 : dev.mysql.com/doc/refman/5.6/en/…
Dub Nazar

또한 변경 innodb_page_size하려면 ibdata*파괴적인 작업 인 재생산이 필요하기 때문에 전체 mysql 서버를 스크 래스 용으로 다시 만들어야합니다 . 자세한 내용은 syslog를 참조하십시오
Matija Nalis 2019 년

2

다른 답변은 질문에 대한 답변입니다. 근본적인 원인 인 잘못된 스키마 디자인에 대해 설명하겠습니다.

열에 배열을 분산하지 마십시오. 여기에는 새 테이블 (플러스 id등) 에서 3 개 열의 10 개 행으로 변환되어야하는 3 * 10 열이 있습니다.

당신의 Main테이블은

id  int(11) No       
name    text    No       
date    date    No       
time    time    No       
schedule    int(11) No       
category    int(11) No       
status  int(11) No       
admin_id    int(11) No 

추가 테이블 ( Top)은

id  int(11) No          -- for joining to Main
seq TINYINT UNSIGNED    -- containing 1..10
img   varchar(255)    No       
title varchar(255)    No       
desc  text    No    
PRIMARY KEY(id, seq)    -- so you can easily find the 10 top_titles

각에는 10 개 (또는 그보다 적거나 더 많은?) 행이 Top있습니다 id.

이렇게하면 원래 문제가 제거되고 스키마가 정리됩니다. (일부 의견에서 논의 된 것처럼 이것은 "정규화"가 아닙니다.)

수행 하지 의 MyISAM로 전환; 그것은 사라질 것입니다.
에 대해 걱정하지 마십시오 ROW_FORMAT.

JOIN여러 열 대신 여러 행을 처리하고 처리 하려면 코드를 변경해야합니다 .


1

AWS RDS에서 MySQL 5.6을 사용하고 있습니다. 파라미터 그룹에서 다음을 업데이트했습니다.

innodb_file_per_table=1
innodb_file_format = Barracuda

파라미터 그룹 변경 사항을 적용하려면 DB 인스턴스를 재부팅해야했습니다.

또한 ROW_FORMAT = COMPRESSED는 지원되지 않습니다. 나는 아래와 같이 DYNAMIC을 사용했고 잘 작동했습니다.

ALTER TABLE nombre_tabla ENGINE=InnoDB ROW_FORMAT=DYNAMIC KEY_BLOCK_SIZE=8

1

데이터베이스 페이지 내에 로컬로 저장된 데이터에 적용되는 InnoDB 테이블의 최대 행 크기는 4KB, 8KB, 16KB 및 32KB에 대해 페이지의 절반보다 약간 작습니다.

16kb 페이지 (기본값)의 경우 다음을 계산할 수 있습니다.

Slightly less than half a page 8126 / Number of bytes to threshold for overflow 767 = 10.59 fields of 767 bytes maximum

기본적으로 다음을 사용하여 행을 최대로 늘릴 수 있습니다.

  • 11 개의 varchar 필드> 767 자 (latin1 = 문자 당 1 바이트) 또는
  • 11 개의 varchar 필드> 255 자 (mysql의 UTF-8 = 문자 당 3 바이트).

필드가> 767 바이트 인 경우에만 오버 플로우 페이지로 오버 플로우됩니다. 767 바이트의 필드가 너무 많으면 파산됩니다 (최대 row_size를 넘어서 전달). latin1에서는 일반적이지 않지만 개발자가주의하지 않으면 utf-8에서는 매우 가능합니다.

이 경우 innodb_page_size를 32kb로 늘릴 수 있다고 생각합니다.

my.cnf :

innodb_page_size=32K

참조 :


0

나도 같은 문제가 발생했습니다. 다음 SQL을 실행하여 문제를 해결합니다.

ALTER ${table} ROW_FORMAT=COMPRESSED;

그러나 나는 당신이 Row Storage 에 대해 알아야한다고 생각합니다 .
열에는 가변 길이 열 (예 : VARCHAR, VARBINARY, BLOB 및 TEXT 유형)과 고정 길이 열의 두 종류가 있습니다 . 다른 유형의 페이지에 저장됩니다.

가변 길이 열은이 규칙의 예외입니다. B- 트리 페이지에 맞추기에는 너무 긴 BLOB 및 VARCHAR와 같은 열은 오버 플로우 페이지라고하는 별도로 할당 된 디스크 페이지에 저장됩니다. 이러한 열을 페이지 외부 열이라고합니다. 이러한 열의 값은 단일 링크 된 오버플로 페이지 목록에 저장되며 이러한 각 열에는 하나 이상의 오버플로 페이지에 대한 자체 목록이 있습니다. 경우에 따라 긴 열 값의 전체 또는 접두사가 B- 트리에 저장되어 스토리지 낭비를 방지하고 별도의 페이지를 읽을 필요가 없습니다.

ROW_FORMAT 설정 목적이

ROW_FORMAT = DYNAMIC 또는 ROW_FORMAT = COMPRESSED로 테이블이 생성되면 InnoDB는 긴 가변 길이 열 값 (VARCHAR, VARBINARY, BLOB 및 TEXT 유형의 경우)을 완전히 오프 페이지에 저장할 수 있으며 클러스터형 인덱스 레코드는 20- 오버 플로우 페이지에 대한 바이트 포인터.

DYNAMIC 및 COMPRESSED 행 형식 에 대해 자세히 알고 싶습니다.


0

열이 많은 SELECT에서 이것이 발생하면 mysql이 임시 테이블을 생성하고 있기 때문일 수 있습니다. 이 테이블이 너무 커서 메모리에 맞지 않으면 기본 임시 테이블 형식 인 InnoDB를 사용하여 디스크에 저장합니다. 이 경우 InnoDB 크기 제한이 적용됩니다.

그런 다음 4 가지 옵션이 있습니다.

  1. 다른 게시물에 명시된대로 innodb 행 크기 제한을 변경하면 서버를 다시 초기화해야합니다.
  2. 더 적은 열을 포함하도록 쿼리를 변경하거나 임시 테이블을 만들지 않도록하십시오 (예 : order by 및 limit 절 제거).
  3. 결과가 메모리에 맞고 디스크에 쓸 필요가 없도록 max_heap_table_size 를 크게 변경 합니다.
  4. 기본 임시 테이블 형식을 MYISAM으로 변경하면 이것이 내가 한 일입니다. my.cnf 변경 :

    internal_tmp_disk_storage_engine=MYISAM

mysql을 다시 시작하면 쿼리가 작동합니다.


0

다음은 관심있는 사람을위한 간단한 팁입니다.

10.3.17-MariaDB를 사용하여 Debian 9에서 Debian 10으로 업그레이드 한 후 Joomla 데이터베이스에서 몇 가지 오류가 발생합니다.

[경고] InnoDB : field테이블 에 필드 를 추가 할 수 없습니다 database. table추가 한 후 행 크기는 인덱스 리프 페이지의 레코드에 대해 허용되는 최대 크기 (8126)보다 큰 8742이기 때문입니다.

경우에 따라 /etc/mysql/mariadb.conf.d/50-server.cnf에 innodb_default_row_format = DYNAMIC을 설정했습니다 (어쨌든 기본값이었습니다)

phpmyadmin을 사용하여 Joomla 데이터베이스의 모든 테이블에 대해 "Optimize table"을 실행했습니다. 이 과정에서 phpmyadmin이 수행 한 테이블 재생이 도움이되었다고 생각합니다. phpmyadmin이 설치되어 있다면 클릭 몇 번이면됩니다.


Joomla 사용자 인 경우 Joomla Stack Exchange에 가입하세요 . 언제든지 새로운 기여자를 사용할 수 있습니다.
mickmackusa
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.