#1071-指定されたキーが長すぎました; キーの最大長は767バイトです


562

次のコマンドを実行したとき:

ALTER TABLE `mytable` ADD UNIQUE (
`column1` ,
`column2`
);

私はこのエラーメッセージを受け取りました:

#1071 - Specified key was too long; max key length is 767 bytes

column1とcolumn2に関する情報:

column1 varchar(20) utf8_general_ci
column2  varchar(500) utf8_general_ci

私は考えてvarchar(20)いる間のみ、21バイトを必要とvarchar(500)のみ501バイトが必要です。したがって、合計バイト数は522であり、767未満です。では、なぜエラーメッセージが表示されたのですか?

#1071 - Specified key was too long; max key length is 767 bytes

5
520バイトではなく2080バイトであり、767バイトをはるかに超えるため、column1 varchar(20)およびcolumn2 varchar(170)を実行できます。文字/バイト相当が必要な場合は、latin1を使用してください
Rahly

3
ここであなたの計算は少し間違っていると思います。mysqlは、1バイトまたは2バイトの追加バイトを使用して値の長さを記録します。列の最大長が255バイト以下の場合は1バイト、255バイトを超える場合は2バイト。VARCHAR(20)は、VARCHAR(500)は、合計1563バイト1502バイト使用し、61バイトを使用するようutf8_general_ciエンコーディングは、文字当たり3つのバイトを必要
lackovic10

3
mysql> select_len、character_set_name from information_schema.character_sets where character_set_name in( 'latin1'、 'utf8'、 'utf8mb4'); maxlen | character_set_name ------ | ------------------- 1 | latin1 ------ | ------------------ 3 | utf8 ------ | ------------------ 4 | utf8mb4
lackovic10

15
'文字/バイト相当が必要な場合は、latin1を使用してください' これは行わないでください。Latin1は本当に、本当にひどい。あなたはこれを後悔するでしょう。
Stijn de Witt

ソリューションについては、stackoverflow.com
a / 52778785/2137210を

回答:


490

MySQLバージョン5.6(およびそれ以前のバージョン)でのInnoDBテーブルのプレフィックス制限は767バイトです。MyISAMテーブルの場合、長さは1,000バイトです。MySQLバージョン5.7以降では、この制限は3072バイトに引き上げられました。

また、utf8mb4でエンコードされた大きなcharまたはvarcharフィールドにインデックスを設定する場合は、インデックスプレフィックスの最大長である767バイト(または3072バイト)を4で除算する必要があることにも注意する必要があります。 utf8mb4文字の最大長は4バイトです。utf8文字の場合、3バイトになるため、インデックスプレフィックスの最大長は254になります。

1つのオプションは、VARCHARフィールドに下限を設定することです。

この問題への応答によると)別のオプションは、全体ではなく、列のサブセットを取得することです。

ALTER TABLE `mytable` ADD UNIQUE ( column1(15), column2(200) );

適用するキーを取得する必要があるので微調整しますが、このエンティティに関するデータモデルを確認して、MySQLの制限に達することなく目的のビジネスルールを実装できるようにする改善点があるかどうかを確認することは価値があるのでしょうか。


4
金額全体ではなく、列のサブセットを指定して適用します。良い解決策です。
スティーブン、

204
これは、長さ制限をはるかに下回るフィールドが長さ制限を超えている理由を説明していません...
Cerin

6
上記で@Cerinが欠落している情報を編集してみましたが、他のユーザーからも欠落していると考えられますが、コメントとして適切であるため拒否されます。500 + 20> 767の理由を理解しようとしている人は、Julienの回答に対するStefan Endrullisのコメントを参照してください。
Letharion、2015年

8
これは問題になる可能性があります。たとえば、フィールド名(255)があり、utf8mb4を使用しているので、名前(191)でこのフィールドに一意を追加します。私は私のユーザーを持っている場合は「IJUE3ump5fiUuCi16jSofYS234MLschW4wsIktKiBrTPOTKBK6Vteh5pNuz1tKjy ... aO500mlJs」そして、他のユーザーが異なるが最後の文字であるこの「IJUE3ump5fiUuCi16jSofYS234MLschW4wsIktKiBrTPOTKBK6Vteh5pNuz1tKjy ... aO500mlJa」で自分の名前を追加して自分の名前を追加します。重複したエントリでスタックしない検証に合格する必要があります。
VEE

28
インデックスの制限は、文字ではなく767 バイトです。また、Mysqlのutf8mb4文字セット(世界の他の地域ではutf8と呼ばれています)では、文字ごとに(最大で)4バイトが必要なので、インデックスを付けることができるのはまでVARCHAR(191)です。Mysqlのutf8文字セット(他の地域では壊れていると呼ばれます)は1文字あたり最大3バイトを必要とするため、それを使用している場合は(必要ありません)、インデックスを作成できますVARCHAR(255)
Stijn de Witt

404

INNODB / Utf-8でフィールドにUNIQUEインデックスを付けようとして問題が発生している場合はVARCHAR(256)、に切り替えVARCHAR(255)ます。255が限界のようです。


247
許可される文字数は、文字セットによって異なります。UTF8は1文字あたり最大3バイト、utf8mb4は最大4バイト、latin1は1バイトのみを使用できます。したがって、utf8の場合、キーの長さは255文字に制限されてい3*255 = 765 < 767ます。
Stefan Endrullis 2014

10
これは私に多くのフラストレーションを救いました-ありがとう。ユーザーが767bの制限に達したと主張してInnoDBを使用していることを考えると、これは受け入れられた回答IMOである必要があります。
TheCarver

8
Stefan Endrullisが述べたように、それは文字セットに依存します。3バイトを使用するUTF8を使用する場合:255x3 = 765は767の制限よりも低く、256x3 = 768はより高いです。しかし、UTF8mb4を使用する場合、255 * 4 = 1020なので、実際のソリューションではありません
bernhardh

25
この答えは正しいです。ただし、255が実際に機能している場合は、MySQLを使用していることを意味しますutf8。基本的な多言語プレーンでのみ文字をエンコードできます。あなたはそれの外にあるキャラクターの問題が発生します。たとえば、彼らが追加している絵文字は、その範囲外だと思います。だからではなく、のへの切り替えVARCHAR(255)にスイッチ、VARCHAR(191) およびへのエンコーディングに切り替えるutf8mb4(実際にはUTF8ですが、MySQLは。compatのバック維持したいです)。
Stijn de Witt

1
複数列の一意制約には役立ちません。また、OPの複数列の一意性制約では機能しません。(合計サイズは825バイトになります)
Barett

351

限界に達したとき。以下を設定します。

  • INNODB utf8 VARCHAR(255)
  • INNODB utf8mb4 VARCHAR(191)

34
これが最良の答えです。シンプルで要点があり、utf8mb4制限も含まれます(これは、絵文字などを受け入れるため、新しいデータベースで最も使用されるエンコーディングです)。
Claudio Holanda

10
767/4〜= 191、および767/3〜= 255
会計士、2017年

11
どこにどのように設定するのですか?
Dinesh Sunny

1
はい、ステートメントENGINE=InnoDB DEFAULT CHARSET=utf8の最後に主キーを指定CREATE TABLEできましたVARCHAR(255)。ありがとう。
xonya

1
誰かが彼に制限191を超えるために+1を与える:)
cagcak

147

MySQLは、文字列の文字あたりのバイト数が最悪の場合を想定しています。MySQLの「utf8」エンコーディングの場合、そのエンコーディングはを超える文字を許可しないため、文字あたり3バイトU+FFFFです。MySQLの「utf8mb4」エンコーディングの場合、これはMySQLが実際のUTF-8と呼ぶものなので、1文字あたり4バイトです。

したがって、「utf8」を使用しているとすると、最初の列はインデックスの60バイトを使用し、2番目の列はさらに1500バイトを使用します。


4
- utf8mb4を使用しているとき、私はそれらを設定する必要があることを、どのおそらく手段(最大で)191 * 4 = 764 <767 191など
アイザック・

2
@Isaacはい、その通りです
morganwahl 2016

2
これは正しい答えかもしれないと思いますが、そのような問題を修正するために何をする必要があるかについて詳しく説明できますか?少なくとも私のようなMySQL初心者にとっては?
アダムグラント

このインデックス制限を回避する方法は1つではありません。ここでの質問は、固有の制約についてです。それらの場合、長さが無制限のテキストの1つの列と、そのテキストのハッシュ(MD5など)を格納する別の列を作成し、そのハッシュ列を一意の制約に使用できます。プログラムがテキストを変更するときにハッシュを最新の状態に保つことを確認する必要がありますが、あまり問題なくそれを処理するさまざまな方法があります。率直に言って、MySQLはそのようなこと自体を実装する必要があるので、あなたがする必要はありません。MariaDBにそのようなものが組み込まれていても、私は驚かないでしょう。
morganwahl 2016年

非常に長いvarchar列の一意のインデックスはまれです。設計上の問題である可能性があるため、なぜ必要なのか考えてください。検索用のインデックスが必要な場合は、191文字以内に収まる「キーワード」フィールドを検討するか、テキストを短い説明と長い/完全なテキストなどに分割します。または、フルテキスト検索が本当に必要な場合は、専用のソフトウェアを使用することを検討してくださいApache Luceneなど。
Stijn de Witt

56

クエリの前にこのクエリを実行します。

SET @@global.innodb_large_prefix = 1;

これにより、制限がに増加し3072 bytesます。


4
グローバルにinnodb_large_prefixに変更することの欠点はありますか?そして、そのDBは「グローバル」ですか、それともすべてのDBが完全にグローバルですか?
SciPhi 2014年

5
非標準の行フォーマットを使用する場合にのみ適用されます。dev.mysql.com/doc/refman/5.5/en/…を参照してください。具体的には、「DYNAMICおよびCOMPRESSED行形式を使用するInnoDBテーブルの場合、このオプションを有効にして、767バイトより長いインデックスキープレフィックスを許可します(最大3072バイト)。」デフォルトの行フォーマットは影響を受けません。
Chris Lear

5
これは私のためによく働いた-詳細とガイドがここで見つけることができます:mechanics.flite.com/blog/2014/07/29/...
CWD

1
この後、mysqlサーバーを再起動する必要がありますか?
SimpleGuy

7
この回答から欠落している重要な詳細。innodb_file_formatでなければならないBARRACUDAとテーブルレベルでは、使用する必要がありますROW_FORMAT=DYNAMICROW_FORMAT=COMPRESSED。ガイドとともに上記の@cwdのコメントを参照してください。
q0rban 2018年

46

Laravelフレームワークのソリューション

Laravel 5.4。*ドキュメントに従って; 次のようbootに、app/Providers/AppServiceProvider.phpファイルのメソッド内でデフォルトの文字列長を設定する必要があります。

use Illuminate\Support\Facades\Schema;

public function boot() 
{
    Schema::defaultStringLength(191); 
}

Laravel 5.4。*のドキュメントに記載されているこの修正の説明:

Laravelはutf8mb4デフォルトで文字セットを使用します。これには、データベースに「絵文字」を格納するためのサポートが含まれます。5.7.7リリースより前のバージョンのMySQLまたは10.2.2リリースより前のMariaDBを実行している場合、MySQLがそれらのインデックスを作成するために、移行によって生成されるデフォルトの文字列長を手動で構成する必要がある場合があります。これを設定するには、Schema::defaultStringLength内でメソッドを呼び出しますAppServiceProvider

または、innodb_large_prefixデータベースのオプションを有効にすることもできます。このオプションを適切に有効にする方法については、データベースのドキュメントを参照してください。


10
@BojanPetkovicまあ、私はLaravelの問題から来たばかりで、この答えは実際に私の問題を解決しました。
mkmnstr 2017年

この答えは素晴らしいです。しかし、誰もが知っていますか?なぜこれが正確に機能するのですか?
UeliDeSchwert

1
@Bobby Laravelのドキュメントでは、見出し「インデックスの長さとMySQL / MariaDB」にその説明が記載されていますlaravel.com/docs/5.4/migrations#creating-indexes
Ali Shaukat

1
@ボビー答えを更新しました。この修正について、laravelのドキュメントによる説明を追加しました。
Ali Shaukat

39

どの文字エンコーディングを使用していますか?一部の文字セット(UTF-16など)は、文字ごとに複数のバイトを使用します。


8
UTF8の場合、文字は最大4バイトを使用できるため、20文字の列は20 * 4 + 1バイトで、500文字の列は500 * 4 + 2バイトです
Thanatos

5
それだけの価値があるので、私は同じ問題を抱えていて、utf8_general_ciからutf8_unicode_ciに切り替えると問題が解決しました。理由はわかりませんが:(
Andresch Serj

11
インデックスのあるVARCHAR(256)列の場合、UNIQUE@ Andreschの場合と同様に、照合順序を変更しても影響はありませんでした。ただし、長さを256から255に減らすことで解決しました。理由がわかりません。767/文字あたり最大4バイトで最大191になるためです。
Arjan

10
255*3 = 765; 256*3 = 768。サーバーが1文字あたり3バイトを想定しているようです、@ Arjan
Amber

21
@Greg:正解ですが、これは詳しく説明する必要があります。UTF-8自体はコードポイントごとに1〜4バイトを使用します。MySQLの「文字セット」(実際にはエンコーディング)には、UTF-8の一部をエンコードできる「utf8」と呼ばれる文字セットがあり、コードポイントごとに1〜3バイトを使用し、BMP外のコードポイントをエンコードすることはできません。また、コードポイントごとに1〜4バイトを使用し、すべてのUnicodeコードポイントをエンコードできる「utf8mb4」と呼ばれる別の文字セットも含まれています。(utf8mb4はUTF-8、utf8はUTF-8の奇妙なバージョンです。)
タナトス

28

varchar(20)には21バイトしか必要ありませんが、varchar(500)には501バイトしか必要ありません。したがって、合計バイト数は522であり、767未満です。では、なぜエラーメッセージが表示されたのですか?

UTF8は、文字列を格納するために文字ごとに3バイトを必要とするため、この場合、20 + 500文字= 20 * 3 + 500 * 3 = 1560バイトであり許容される767バイトを超えます。

UTF8の制限は767/3 = 255文字です。1文字あたり4バイトを使用するUTF8mb4の場合、それは767/4 = 191文字です。


制限よりも長い列を使用する必要がある場合、この問題には2つの解決策があります。

  1. 使用「安く」をコードする(文字あたり少ないバイトが必要です1)
    私の場合は、私が唯一使用して、記事のSEOの文字列を含む列に一意のインデックスを追加するために必要な[A-z0-9\-]私が使用し、SEOのための文字をlatin1_general_ci文字ごとに1つのだけのバイトを使用しますしたがって、列の長さは767バイトになります。
  2. 列からハッシュを作成し、
    その上でのみ一意のインデックスを使用する私の他のオプションは、SEOのハッシュを格納する別の列を作成することでした。この列には、UNIQUESEO値が一意であることを確認するためのキーがあります。KEYルックアップを高速化するために、元のSEO列にもインデックスを追加します。

これでうまくいきました。私はvarchar(256)を持っていて、それをvarchar(250)に変更する必要がありました。
MaRmAR 2017年

25

エラーメッセージが表示される理由に関する回答は、すでに多くのユーザーから回答されています。私の答えは、それを修正してそのまま使用する方法についてです。

このリンクから参照してください

  1. MySQLクライアント(またはMariaDBクライアント)を開きます。コマンドラインツールです。
  2. パスワードを聞かれますので、正しいパスワードを入力してください。
  3. このコマンドを使用してデータベースを選択します use my_database_name;

データベースが変更されました

  1. set global innodb_large_prefix=on;

クエリは正常、0行が影響を受けた(0.00秒)

  1. set global innodb_file_format=Barracuda;

クエリは正常、0行が影響を受けた(0.02秒)

  1. 管理を容易にするために、phpMyAdminなどのデータベースに移動します。> [データベース]> [テーブル構造の表示]> [ 操作 ]タブに移動します。> ROW_FORMATDYNAMICに変更し、変更を保存します。
  2. テーブルの構造タブに移動し、[ 一意 ]ボタンをクリックします。
  3. できました。これでエラーは発生しなくなりました。

この修正の問題は、dbを別のサーバーに(たとえば、localhostから実際のホストに)エクスポートし、そのサーバーでMySQLコマンドラインを使用できない場合です。そこで動作させることはできません。


それでも、クエリの上に入力した後にエラーしている場合は、「phpMyAdminの」へ行くしよう>あなたの好みに「照合」を設定(私のために私は「utf8_general_ci」を使用)>(でもそのすでにUTF8場合)、[適用]をクリックします
アンソニー・カル

私はあなたの指示で機能するツールを使用していませんが、実際に問題を修正する人々を助けるために投票しています。問題の原因については無限の説明がありますが、実際に解決する方法はほとんどありません。
Teekin

20
Specified key was too long; max key length is 767 bytes

latin-1文字セットを使用する場合にのみ、1バイトが1文字に等しいため、このメッセージが表示されます。を使用utf8すると、キー列を定義するときに各文字が3バイトと見なされます。を使用する場合utf8mb4、キー列を定義するときに、各文字は4バイトと見なされます。したがって、キーフィールドが許可しようとしているバイト数を決定するには、キーフィールドの文字制限に1、3、または4(この例では)を掛ける必要があります。uft8mb4を使用している場合、ネイティブのInnoDB主キーフィールドに定義できるのは191文字のみです。ただ767バイトを突破しないでください。


17

インポートファイルutf8mb4utf8に置き換えます。

ここに画像の説明を入力してください


なぜ正確にそれをする必要があるのですか?さらに、これにマイナス面がある場合(私はそれを想定しています)、これについて言及する必要があります
ニコ・ハーセ

16

あなたは長い列のmd5の列を追加することができます


これにより、これらの列に対して範囲スキャンを実行できないことに注意してください。VARCHARのプレフィックス長により、この特性を維持しながら、インデックスで疑わしい一致が発生する可能性があります(スキャンと行のルックアップによってそれらが排除されます)(受け入れられた回答を参照)。(これは本質的に手動で実装されたハッシュインデックスであり、残念なことにMysQLはInnoDBテーブルではサポートしていません。)
Thanatos

テスト目的でH2との互換性を維持する必要があり、ハッシュ列を使用するとうまく機能することがわかったため、プレフィックスインデックスを使用できませんでした。悪意のあるユーザーによる衝突の発生を防ぐために、MD5ではなくSHA1などの衝突耐性機能を使用することを強くお勧めします。クエリの1つが完全な列値ではなくハッシュ値のみをチェックする場合、インデックスの衝突が悪用されてデータがリークする可能性があります。
リトルマイク

13

utf8mb4を使用してVARCHAR(255)フィールドにUNIQUEインデックスを追加しようとしたときに、この問題が発生しました。問題の概要はすでにここにありますが、これを理解して解決するための実用的なアドバイスを追加したいと思います。

utf8mb4を使用する場合、文字は4バイトとしてカウントされますが、utf8では、3バイトとしてカウントされます。InnoDBデータベースには、インデックスには767バイトしか含めることができないという制限があります。したがって、utf8を使用すると、255文字(767/3 = 255)を格納できますが、utf8mb4を使用すると、191文字(767/4 = 191)しか格納できません。

VARCHAR(255)utf8mb4を使用してフィールドに通常のインデックスを追加することは完全に可能ですが、次のように、インデックスサイズが191文字で自動的に切り捨てられunique_keyます。

191文字で切り捨てられたインデックスを示すSequel Proのスクリーンショット

通常のインデックスは、MySQLがデータをより迅速に検索できるようにするためだけに使用されるため、これは問題ありません。フィールド全体にインデックスを付ける必要はありません。

では、MySQLが通常のインデックスのインデックスを自動的に切り捨てるのに、一意のインデックスに対してそれを行おうとすると明示的なエラーがスローされるのはなぜですか?まあ、MySQLが挿入または更新される値がすでに存在するかどうかを把握できるようにするには、実際には値の一部ではなく、値全体にインデックスを付ける必要があります。

結局のところ、フィールドに一意のインデックスが必要な場合は、フィールドの内容全体がインデックスに収まる必要があります。utf8mb4の場合、これはVARCHARフィールド長を191文字以下に減らすことを意味します。そのテーブルまたはフィールドにutf8mb4が必要ない場合は、それをutf8にドロップして、長さ255のフィールドを保持することができます。


11

これが私の元の答えです:

私はデータベースを削除して次のように再作成するだけで、エラーはなくなりました。

drop database if exists rhodes; create database rhodes default CHARACTER set utf8 default COLLATE utf8_general_ci;

ただし、すべてのケースで機能するわけではありません。

これは、文字セットutf8(または utf8mb4)が指定されたVARCHAR列でインデックスを使用する際の問題であり、特定の長さを超える文字を持つVARCHAR列で使用されます。の場合utf8mb4、その特定の長さは191です。

MySQLデータベースで長いインデックスを使用する方法の詳細については、この記事の「長いインデックス」セクションを参照してください。http//hanoian.com/content/index.php/24-automate-the-converting-a-mysql-database-文字セットからutf8mb4


openmeetingsセットアップの問題を解決しました(ところで、私の夜を保存しました:-)
Ludo

11

5つの回避策:

5.7.7で制限が引き上げられました(MariaDB 10.2.2?)。そして、5.6(10.1)のいくつかの作業でそれを増やすことができます。

CHARACTER SET utf8mb4を使用しようとしたために制限に達した場合。次に、エラーを回避するために、次のいずれかを実行します(それぞれに欠点があります)。

  Upgrade to 5.7.7 for 3072 byte limit -- your cloud may not provide this;
  Change 255 to 191 on the VARCHAR -- you lose any values longer than 191 characters (unlikely?);
  ALTER .. CONVERT TO utf8 -- you lose Emoji and some of Chinese;
  Use a "prefix" index -- you lose some of the performance benefits.
  Or... Stay with older version but perform 4 steps to raise the limit to 3072 bytes:

SET GLOBAL innodb_file_format=Barracuda;
SET GLOBAL innodb_file_per_table=1;
SET GLOBAL innodb_large_prefix=1;
logout & login (to get the global values);
ALTER TABLE tbl ROW_FORMAT=DYNAMIC;  -- (or COMPRESSED)

- http://mysql.rjweb.org/doc.php/limits#767_limit_in_innodb_indexes


10

私はこの問題を修正しました:

varchar(200) 

交換された

varchar(191)

200を超えるすべてのvarcharは、それらを191に置き換えるか、テキストに設定します。


これは私にとってもうまくいきました。私はvarchar(250)を持っていましたが、データはそれほど長くありませんでした。varchar(100)に変更しました。アイデアをありがとう:)
アルンバジルラル

7

私はこのトピックについていくつかの検索を行いましたが、最終的にいくつかのカスタム変更を取得

MySQL Workbench 6.3.7バージョンの場合、グラフィカルな中間フェーズが利用可能です

  1. Workbenchを起動し、接続を選択します。
  2. 管理またはインスタンスに移動し、オプションファイルを選択します。
  3. Workbenchが構成ファイルを読み取る許可を求めてきたら、OKを2回押して許可します。
  4. 中央に管理者オプションファイルウィンドウが表示されます。
  5. 一般セクションでチェックされていない場合は、InnoDBタブに移動し、innodb_large_prefixをチェックします。
  6. innodb_default_row_formatオプションの値をDYNAMICに設定します。

6.3.7より前のバージョンの場合、直接オプションは使用できないため、コマンドプロンプトを使用する必要があります

  1. 管理者としてCMDを開始します。
  2. mysqlサーバーがインストールされているディレクタに移動するほとんどの場合、C:\ Program Files \ MySQL \ MySQL Server 5.7 \ binにあるため、コマンドは "cd \" "cd Program Files \ MySQL \ MySQL Server 5.7 \ bin"です。
  3. ここで、コマンドmysql -u userName -p databasescheemaを実行します。これで、各ユーザーのパスワードを要求されました。パスワードを入力し、mysqlプロンプトに入力します。
  4. 以下のコマンドを1つずつ入力して、いくつかのグローバル設定を設定する必要があります。set global innodb_large_prefix = on; グローバルinnodb_file_format = barracudaを設定します。グローバルinnodb_file_per_table = trueを設定します。
  5. 最後に、必要なテーブルのROW_FORMATをデフォルトで変更する必要があります。デフォルトでは、COMPACTをDYNAMICに設定する必要があります。
  6. 次のコマンドを使用します。altertable table_name ROW_FORMAT = DYNAMIC;
  7. できた

これが見つかりません:6. innodb_default_row_formatオプションの値をDYNAMICに設定します。
Adrian Cid Almaguer 2017年

使用するset global innodb_default_row_format = DYNAMIC;と、次のメッセージが表示されます。エラー1193(HY000):不明なシステム変数 'innodb_default_row_format'
Adrian Cid Almaguer

どのようにワークベンチからcmdにエラーが発生しましたか?私はそれが直接オプションを持つワークベンチからそれをしました。
アビシェーク

私はWorkbenchのオプションが表示されないので、CMDからそれを行う
エイドリアンシドAlmaguer

1
このvarがv5.7.9で導入された問題を確認し、v5.6.33バージョンを持っています。ありがとう
Adrian Cid Almaguer

7

Laravel 5.7から6.0の場合

従うべき手順

  1. に移動しApp\Providers\AppServiceProvider.phpます。
  2. これをuse Illuminate\Support\Facades\Schema;一番上のプロバイダーに追加します 。
  3. Boot関数の内部これを追加 Schema::defaultStringLength(191);

そのすべて、お楽しみください。


Laravel 5.8でも動作しました。
Neo

これは悪い解決策です。理由:インデックスは無限に長くなることを意図していません。一意のインデックスを何かに適用するときは、ほとんどの場合、インデックスを固定しておく必要があります。それはあなたがユニークなものを作るべきではないことを意味しますemailが、あなたはメールをハッシュしてそれをユニークにするべきです。生の文字列データとは異なり、ハッシュは固定幅であり、インデックスを付けて問題なく一意にすることができます。問題を理解するのではなく、スケーリングしないひどい慣行を広めています。
NB

5

照合順序を変更します。ほとんどすべてをサポートするutf8_general_ciを使用できます


「ほぼ」は、これが長期的な解決策ではないというかなり良いヒントです
ニコ・ハーセ

4

テーブルを作成utf8mb4するutf8ときに変更するだけで問題は解決しました。たとえば、次のようCREATE TABLE ... DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;CREATE TABLE ... DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;


4

これを修正するために、これは私にとって魅力のように機能します。

ALTER DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;

私の問題もデータベースの照合順序であることを確認しました。説明はありません。私はmysql v5.6.32を使用しており、DB照合はutf8mb4_unicode_ciでした。
mahyard

2

以下に示す列に基づいて、これらの2つの変数文字列列はutf8_general_ci照合を使用しています(utf8文字セットが暗示されています)。

MySQLでは、utf8文字セットは各文字に最大3バイトを使用します。したがって、MySQLが許可する767バイトよりもはるかに大きい500 * 3 = 1500バイトを割り当てる必要があります。このため、この1071エラーが発生します。

つまり、すべての文字セットが1バイト表現であるとは限らないため(想定どおり)、文字セットのバイト表現に基づいて文字数を計算する必要がありutf8ます。MySQLのIE は、文字あたり最大3バイト、767 /3≈255を使用します。文字、およびの場合utf8mb4は最大4バイトの表現、767 /4≈191文字。

MySQLが

column1 varchar(20) utf8_general_ci
column2  varchar(500) utf8_general_ci

1

このクエリは、最大長に違反するインデックスを持つ列を検出するのに役立ちます。

SELECT
  c.TABLE_NAME As TableName,
  c.COLUMN_NAME AS ColumnName,
  c.DATA_TYPE AS DataType,
  c.CHARACTER_MAXIMUM_LENGTH AS ColumnLength,
  s.INDEX_NAME AS IndexName
FROM information_schema.COLUMNS AS c
INNER JOIN information_schema.statistics AS s
  ON s.table_name = c.TABLE_NAME
 AND s.COLUMN_NAME = c.COLUMN_NAME 
WHERE c.TABLE_SCHEMA = DATABASE()
  AND c.CHARACTER_MAXIMUM_LENGTH > 191 
  AND c.DATA_TYPE IN ('char', 'varchar', 'text')

1

sql_modeようなものかどうか確認してください

sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

もしそうなら、に変更

sql_mode=NO_ENGINE_SUBSTITUTION

または

my.cnfファイルを変更してサーバーを再起動します(以下を入力)

innodb_large_prefix=on

1

私の場合、Linuxリダイレクトの出力/入力文字を使用してデータベースをバックアップしているときにこの問題が発生しました。したがって、以下のように構文を変更します。PS:LinuxまたはMac端末を使用します。

バックアップ(>リダイレクトなし)

# mysqldump -u root -p databasename -r bkp.sql

復元(<リダイレクトなし)

# mysql -u root -p --default-character-set=utf8 databasename
mysql> SET names 'utf8'
mysql> SOURCE bkp.sql

「指定されたキーが長すぎました。キーの最大長は767バイトです」という単純なエラーがなくなりました。


1

インデックスの長さとMySQL / MariaDB


Laravelは、デフォルトでutf8mb4文字セットを使用します。これには、データベースに「絵文字」を格納するためのサポートが含まれます。5.7.7リリースより前のバージョンのMySQLまたは10.2.2リリースより前のMariaDBを実行している場合、MySQLがそれらのインデックスを作成するために、移行によって生成されるデフォルトの文字列長を手動で構成する必要がある場合があります。AppServiceProvider内のSchema :: defaultStringLengthメソッドを呼び出して、これを構成できます

use Illuminate\Support\Facades\Schema;

/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    Schema::defaultStringLength(191);
}

または、データベースのinnodb_large_prefixオプションを有効にすることもできます。このオプションを適切に有効にする方法については、データベースのドキュメントを参照してください。

ブログからの参照: https : //www.scratchcode.io/specified-key-too-long-error-in-laravel/

公式のlaravelドキュメントからの参照: https ://laravel.com/docs/5.7/migrations


0

次のようなものを作成している場合:

CREATE TABLE IF NOT EXISTS your_table (
  id int(7) UNSIGNED NOT NULL AUTO_INCREMENT,
  name varchar(256) COLLATE utf8mb4_bin NOT NULL,
  PRIMARY KEY (id),
  UNIQUE KEY name (name)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1 ROW_FORMAT=FIXED;

それはのようなものでなければなりません

CREATE TABLE IF NOT EXISTS your_table (
      id int(7) UNSIGNED NOT NULL AUTO_INCREMENT,
      name varchar(256) COLLATE utf8mb4_bin NOT NULL,
      PRIMARY KEY (id)
    ) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1 ROW_FORMAT=FIXED;

しかし、コードからその列の一意性を確認するか、varchar列のMD5またはSHA1として新しい列を追加する必要があります


3
その後、あなたのユニークなキーは失われました。私はより良い方法は、単に191に名前の長さを短縮されたと思う
haudoing

1
それがネイティブDB機能である場合、プログラムで一意性をチェックするのはなぜですか?
パヴェルTomkiel

0

接頭辞の制限により、このエラーが発生します。767バイトは、5.7より前のMySQLバージョンでのInnoDBテーブルのプレフィックスの制限です。MyISAMテーブルの場合、長さは1,000バイトです。MySQLバージョン5.7以降では、この制限は3072バイトに引き上げられました。

エラーが発生したサービスで以下を実行すると、問題が解決するはずです。これはMYSQL CLIで実行する必要があります。

SET GLOBAL innodb_file_format=Barracuda;
SET GLOBAL innodb_file_per_table=on;
SET GLOBAL innodb_large_prefix=on;

-1

問題のあるインデックスフィールドのCHARSETを "latin1"に変更します。
つまり、ALTER TABLE tbl CHANGE myfield myfield varchar(600)CHARACTER SET latin1 DEFAULT NULL;
latin1は、1文字に4バイトではなく1バイトを使用します


5
そして、彼が非Latin1文字を挿入しようとするとどうなるでしょうか。
パヴェルTomkiel

4
これは最悪のことです。絶対にしないでください。
セバス

1
私の場合、16進文字のみのパス名を格納する列にあるので、これは誰かの解決策になるかもしれません。それは本当に保存したいものに依存します...
codewandler

latin1を使用することは2016ADでは解決策ではないため、私はこれに反対票を投じなければなりませんでした。2007年にデータベースをlatin1からutf8に変換しなければならなかった時期については、恐ろしい悪夢がまだあります。きれいじゃない。全然。
賭ける

ビットコインアドレスとトランザクションIDを格納する2つの列の一意のインデックスで同じ問題が発生しました。これらは常にASCII文字であるため、これらの列にはlatin1を使用します。賛成票。
alexg 2016

-2

innodb_log_file_size最近変更した場合は、機能していた以前の値を復元してみてください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.