「Mysql行サイズが大きすぎます」の制限を変更


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 2013年

「行サイズが大きすぎます(> 8126)。一部の列をTEXTまたはBLOBに変更するか、ROW_FORMAT = DYNAMICまたはROW_FORMAT = COMPRESSEDを使用すると解決する場合があります。現在の行形式では、768バイトのBLOBプレフィックスがインラインで保存されます。
Lasha Kurt

少なくともコメントとして、他の詳細を投稿に追加できますか?
Eineki 2013年

1
このデータが別のテーブルにある場合は、代わりに外部キーを使用することを検討してください。これにより、行サイズが大幅に減少し、データベーススキーマが正規化されます。
ディディエルク2013年

1
@AL:おっと、あなたは正しいです-他の投票に近い投票をしてください
pathikrit

回答:


120

serverfaultについても質問されました。

MySQLの行サイズについて詳しく説明しているこの記事をご覧になることをお勧めします。TEXTまたはBLOBフィールドを使用しても、ページ内の各フィールドの最初の768バイトをインラインで格納するため、行サイズは8K(InnoDBの制限)を超える可能性があることに注意することが重要です。

これを修正する最も簡単な方法は 、InnoDBでバラクーダファイル形式を使用することです。これは基本的に、最初の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の部分は重要であり、フォーマットをバラクーダに変更することと密接に関連しています。これがないと、MySQLは静かにAntelopeを使用し続けます。
Nick

1
@Eduardo最初にデータをバックアップすることをお勧めします。しかし、そうです、あなたは本番でもこれを行うことができます!
hjpotter92 2016

3
innodb_file_per_table=1このオプションをアクティブにするために使用します。
Stijn Geukens

2
これが問題の解決を保証するものではありません。これらの設定を追加するが、エラーを再現できるスクリプトの例については、この投稿を参照してください。
Cerin

1
@ user1183352上記の返信を更新しました。これについて深く掘り下げるようにもう一度思い出させてくれてありがとう。:)
hjpotter92

61

最近この問題に遭遇し、別の方法で解決しました。MySQLバージョン5.6.20を実行している場合、システムに既知のバグがあります。MySQLのドキュメントを見る

重要バグ#69477により、外部に保存された大きなBLOBフィールドに対するREDOログの書き込みにより、最新のチェックポイントが上書きされる可能性があります。このバグに対処するために、MySQL 5.6.20で導入されたパッチは、REDOログBLOB書き込みのサイズをREDOログファイルサイズの10%に制限します。この制限の結果、innodb_log_file_sizeは、テーブルの行にある最大のBLOBデータサイズの10倍に、他の可変長フィールド(VARCHAR、VARBINARY、およびTEXTタイプのフィールド)を加えた値に設定する必要があります。

私の状況では、問題のブロブテーブルは約16MBでした。したがって、私がそれを解決した方法は、my.cnfに行を追加することでした。これにより、少なくとも10倍の量が確保され、その後、次のようになります。

innodb_log_file_size = 256M


見つけて。パラメータlongblobを増やすと、フィールドの「行サイズが大きすぎます」というエラーが消えましたinnodb_log_file_size。また、5.6.20を実行していました。
adamup

ありがとう。Homebrew 5.6.21を実行していたときに、パラメータを変更すると問題が修正されました。
nanoman 2014年

このエラーを修正するには、これと@ hjpotter92の両方の回答が必要でした。
セリン

ありがとう。5.6.21を実行していて、このソリューションが役立ちました。
petiar 2015年

これでも私の問題は解決しませんでした。同様のスレッドで見たように、VARCHARフィールドの多くをTEXTに置き換えることを検討しています。
PDoria 2017年

28

my.cnfファイルに以下を設定し、mysqlサーバーを再起動します。

innodb_strict_mode=0

2
innodb_strict_mode=0->スペースなし。それ以外の場合、mariaDB 10.2を再起動するとエラーが発生します:-P
Pathros

私はmariadbを試していません。MySQLの場合、スペースを削除する必要はありません。
カール

1
ドキュメントによると、strictモードを無効にすると、エラーと警告が表示されなくなるだけなので、問題を解決できないようです。 download.nust.na/pub6/mysql/doc/innodb-plugin/1.1/en/...
ジョアン・テイシェイラ

2
これは機能しているようで、問題なくテーブルを作成してデータを保存できます
Chris Muench

@ジョアン、それはもっと多くのことをします..dev.mysql.com/doc/refman/8.0/en/…
Karl

24

エンジンを切り替えて、InnoDBの代わりにMyISAMを使用できる場合、それが役立つはずです。

ENGINE=MyISAM

MyISAMには2つの警告があります(おそらくそれ以上):

  1. トランザクションは使用できません。
  2. 外部キー制約は使用できません。

5
トランザクションと外部キーの制約がなくてもかまわない場合は問題ありません。ただし、MyISAMに切り替えるときにこれらを失うことに注意してください。
wobbily_col

このアドバイスは正気ではありません-少なくともフレーズは警告になります!トランザクションとforegithキーの制約は、この形式の問題の中で最も少ないものです。
Hassan Syed 2016年

この回答に反対投票しました。更新して、関連するすべての警告に言及してください。このアドバイスに従った人は誰でも、私がどのプロダクションシステムでも使用しないフォーマットに切り替えます。
Remco Wendt 2017年

2
そしてMyISAMは廃止されます。
リックジェームズ

2
私のために働いた。私の場合、長さが約10のフィールドが300以上ありました。この表には関係がないため、MyISAMへの切り替えが修正されました。
Robert Saylor

12

私は素晴らしい答えを共有したいと思います、それは役に立つかもしれません。クレジットBill Karwinはこちらを参照してください/dba/6598/innodb-create-table-error-row-size-too-large

それらはInnoDBファイル形式によって異なります。現在、AntelopeおよびBarracudaと呼ばれる2つの形式があります。

中央のテーブルスペースファイル(ibdata1)は常にアンテロープ形式です。file-per-tableを使用する場合、my.cnfでinnodb_file_format = Barracudaを設定することにより、個々のファイルにバラクーダ形式を使用させることができます。

基本的なポイント:

  1. InnoDBデータの1つの16KBページは、少なくとも2行のデータを保持する必要があります。さらに、各ページには、ページチェックサムやログシーケンス番号などを含むヘッダーとフッターがあります。ここで、1行あたり8KB未満の制限を取得します。

  2. INTEGER、DATE、FLOAT、CHARなどの固定サイズのデータ​​型は、このプライマリデータページに格納され、行サイズ制限にカウントされます。

  3. VARCHAR、TEXT、BLOBなどの可変サイズのデータ​​型はオーバーフローページに格納されるため、行サイズの制限に完全にはカウントされません。アンテロープでは、オーバーフローページに格納されるだけでなく、最大768バイトのそのような列がプライマリデータページに格納されます。Barracudaは動的な行形式をサポートしているため、プライマリデータページに格納できるのは20バイトのポインタのみです。

  4. 可変サイズのデータ​​型にも、長さをエンコードするために1バイト以上のプレフィックスが付いています。また、InnoDB行フォーマットにはフィールドオフセットの配列もあります。そのため、多かれ少なかれ彼らのウィキに文書化された内部構造があります。

バラクーダネットワークスは、オーバーフローデータのストレージ効率をさらに高めるために、ROW_FORMAT = COMPRESSEDもサポートしています。

また、適切に設計されたテーブルが行サイズの制限を超えたのを見たことがないこともコメントする必要があります。First Normal Formの繰り返しグループの条件に違反しているのは、強い「コードのにおい」です。


7

私は同じ問題を抱えていました、これは私のためにそれを解決しました:

ALTER TABLE `my_table` ROW_FORMAT=DYNAMIC;

MYSQL ドキュメントから:

DYNAMIC行形式は、行が全体に収まる場合は(COMPACTおよびREDUNDANT形式と同様に)行全体をインデックスノードに格納する効率を維持しますが、この新しい形式は、Bツリーノードに大量のデータバイトを埋める問題を回避します。長い列。DYNAMIC形式は、長いデータ値の一部がページ外に格納される場合、通常はすべての値をページ外に格納することが最も効率的であるという考えに基づいています。DYNAMIC形式では、短い列がBツリーノードに残る可能性が高く、特定の行に必要なオーバーフローページの数が最小限になります。


...しかし、あなたは別のファイル形式を持っている必要があるので、あなたはすでにバラクーダにいますか?、私はそのコマンドをしようとエラーが出る原因と言って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ですが、実際にはそうだったと思います。
テッド

いいですね、これが良い答えだと思うなら、賛成票を入れて、有効な応答として受け入れてください、ありがとう!
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の再起動でエラーが発生したため、回線が機能しませんでした。代わりに、ここで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/...
ダブナザール

また、変更をinnodb_page_size行うとibdata*再構築が必要になるため、破壊的な操作であるため、mysqlサーバー全体をscracth用に再作成する必要があります。詳細については、syslogをご覧ください
Matija Nalis

2

他の回答は、尋ねられた質問に対処します。根本的な原因である、スキーマの設計の悪さについて説明します。

列をまたがって配列を広げないでください。ここには、新しいテーブルで3列の10行に変換する必要がある3 * 10列があります(プラスidなど)

あなたの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バイトあたり1バイト)または
  • 11のvarcharフィールド> 255文字(mysqlではutf-8 = 1文字あたり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;

しかし、私は行ストレージについて知っておくべきだと思います。
列には、可変長列(VARCHAR、VARBINARY、BLOBおよびTEXT型など)と固定長列の 2種類があります。それらは、さまざまなタイプのページに保管されます。

可変長列はこのルールの例外です。Bツリーページに収めるには長すぎるBLOBやVARCHARなどの列は、オーバーフローページと呼ばれる個別に割り当てられたディスクページに格納されます。このような列をページ外列と呼びます。これらの列の値は、オーバーフローページの単一リンクリストに格納され、そのような各列には、1つ以上のオーバーフローページの独自のリストがあります。場合によっては、長い列値のすべてまたはプレフィックスが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

ここに興味のある人のための簡単なヒントがあります:

Debian 9から10.3.17-MariaDBを含むDebian 10にアップグレードした後、Joomlaデータベースからいくつかのエラーが発生しました。

[警告] InnoDB:fieldテーブルにフィールドを追加できませんdatabasetable追加後の行サイズは8742であり、これはインデックスリーフページのレコードの最大許容サイズ(8126)より大きいためです。

念のため、/ etc / mysql / mariadb.conf.d / 50-server.cnfにinnodb_default_row_format = DYNAMICを設定しました(とにかくデフォルトでした)

phpmyadminを使用して、Joomlaデータベースのすべてのテーブルに対して「テーブルの最適化」を実行しました。その過程でphpmyadminによって行われたテーブルの再作成が役立ったと思います。phpmyadminがインストールされている場合は、数回クリックするだけです。


Joomlaユーザーの方は、是非ご参加ください Joomlaのスタック交換-私たちは常に新しい貢献者を使用することができます。
mickmackusa
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.