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


102

このタイトルの質問は以前に回答されたことは知っていますが、読んでください。投稿する前に、このエラーに関する他のすべての質問/回答を完全に読みました。

次のクエリで上記のエラーが発生します。

CREATE TABLE IF NOT EXISTS `pds_core_menu_items` (
  `menu_id` varchar(32) NOT NULL,
  `parent_menu_id` int(32) unsigned DEFAULT NULL,
  `menu_name` varchar(255) DEFAULT NULL,
  `menu_link` varchar(255) DEFAULT NULL,
  `plugin` varchar(255) DEFAULT NULL,
  `menu_type` int(1) DEFAULT NULL,
  `extend` varchar(255) DEFAULT NULL,
  `new_window` int(1) DEFAULT NULL,
  `rank` int(100) DEFAULT NULL,
  `hide` int(1) DEFAULT NULL,
  `template_id` int(32) unsigned DEFAULT NULL,
  `alias` varchar(255) DEFAULT NULL,
  `layout` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`menu_id`),
  KEY `index` (`parent_menu_id`,`menu_link`,`plugin`,`alias`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

誰もがなぜ、どのようにそれを修正するのか考えていますか?問題は、この同じクエリがローカルマシンで完全に機能し、以前のホストでも同様に機能したことです。Btw.itは成熟したプロジェクト-phpdevshell-からのものです。そのため、これらの人たちは彼らが何をしているか知っていると思いますが、あなたは決して知りません。

手がかりはありがたいです。

私はphpMyAdminを使用しています。

回答:


170

@Devartが言うように、インデックスの全長が長すぎます。

簡単に言えば、インデックスは非常に大きくて非効率になるため、このような長いVARCHARカラムにインデックスを付けないでください。

ベストプラクティスは、プレフィックスインデックスを使用して、データの左側の部分文字列のみにインデックスを付けることです。とにかく、ほとんどのデータは255文字よりはるかに短くなります。

インデックスを定義するときに、列ごとにプレフィックス長を宣言できます。例えば:

...
KEY `index` (`parent_menu_id`,`menu_link`(50),`plugin`(50),`alias`(50))
...

しかし、特定の列に最適な接頭辞の長さは何ですか?確認する方法は次のとおりです。

SELECT
 ROUND(SUM(LENGTH(`menu_link`)<10)*100/COUNT(`menu_link`),2) AS pct_length_10,
 ROUND(SUM(LENGTH(`menu_link`)<20)*100/COUNT(`menu_link`),2) AS pct_length_20,
 ROUND(SUM(LENGTH(`menu_link`)<50)*100/COUNT(`menu_link`),2) AS pct_length_50,
 ROUND(SUM(LENGTH(`menu_link`)<100)*100/COUNT(`menu_link`),2) AS pct_length_100
FROM `pds_core_menu_items`;

これは、menu_link列内で指定された文字列長を超えない行の割合を示します。次のような出力が表示される場合があります。

+---------------+---------------+---------------+----------------+
| pct_length_10 | pct_length_20 | pct_length_50 | pct_length_100 |
+---------------+---------------+---------------+----------------+
|         21.78 |         80.20 |        100.00 |         100.00 |
+---------------+---------------+---------------+----------------+

これは、文字列の80%が20文字未満であり、すべての文字列が50文字未満であることを示しています。したがって、プレフィックス長が50を超えるインデックスを作成する必要はなく、255文字の完全な長さのインデックスを作成する必要もありません。

PS:INT(1)and INT(32)データ型は、MySQLに関する別の誤解を示しています。数値引数は、列に許可されているストレージまたは値の範囲に関連する影響を与えません。 INTは常に4バイトであり、常に-2147483648〜2147483647の値を許可します。数値引数は、表示中の値のパディングに関するものであり、ZEROFILLオプションを使用しない限り効果がありません。


17
詳しい説明ありがとうございます。問題を解決することに加えて、私はまた何か価値のあることを学びました。
CodeVirtuoso

本当に、インデックスを設定する必要がある長さを見つけるための非常に便利なクエリ。これを何度か使用して、インデックスの最適な長さを決定しました。共有していただきありがとうございます!
Niraj Kumar

1
文字列が実際にどのくらいの長さであるかを測定するための便利なクエリには、微妙なバグがあります。つまり、それらはすべて存在します。一部がnullの場合、計算がスローされ、短い文字列が過小評価されます。count(*)の代わりにcount([field_name])を使用したい。
D Mac

最初の「プレフィックス」インデックス以外は使用しません。
リックジェームズ

28

このエラーは、インデックスの長さがindex1000バイトを超えていることを意味します。MySQLとストレージエンジンにはこの制限がある場合があります。MySQL 5.5で同様のエラーが発生しました-「指定されたキーが長すぎます。このスクリプトを実行したときの最大キー長は3072バイトです:

CREATE TABLE IF NOT EXISTS test_table1 (
  column1 varchar(500) NOT NULL,
  column2 varchar(500) NOT NULL,
  column3 varchar(500) NOT NULL,
  column4 varchar(500) NOT NULL,
  column5 varchar(500) NOT NULL,
  column6 varchar(500) NOT NULL,
  KEY `index` (column1, column2, column3, column4, column5, column6)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

UTF8はマルチバイトで、キーの長さはこのように計算されます-500 * 3 * 6 = 9000バイト。

ただし、次のクエリは機能します。

CREATE TABLE IF NOT EXISTS test_table1 (
  column1 varchar(500) NOT NULL,
  column2 varchar(500) NOT NULL,
  column3 varchar(500) NOT NULL,
  column4 varchar(500) NOT NULL,
  column5 varchar(500) NOT NULL,
  column6 varchar(500) NOT NULL,
  KEY `index` (column1, column2, column3, column4, column5, column6)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

... CHARSET = latin1を使用したため、この場合、キーの長さは500 * 6 = 3000バイトです。


7
返信ありがとうございます。これは機能しますが、utf8文字セットをあきらめることを犠牲にしてください。この制限はどうにかして克服できますか(私は完全なサーバーアクセス権があります)、それは正当な理由がありますか?
CodeVirtuoso、2012年

4
これはひどいアドバイスです。文字セットとは何か、そしてこれが将来どのようにして大きな問題を引き起こすかを学んでください。混合文字セットデータベースは、結合または副選択を使用するときに問題を引き起こすだけでなく、データを正規化されていない形式にし、後で修正することはほぼ不可能です。
ジェフリー

16

私はこの問題を抱えていて、次のようにして解決しました:

原因

MySQLには、MyISAM、UTF8文字セット、インデックスに関連する既知のバグがあり、ここで確認できます。

解決

  • MySQLがInnoDBストレージエンジンで構成されていることを確認します。

  • 新しいテーブルが常に適切に作成されるように、デフォルトで使用されるストレージエンジンを変更します。

    set GLOBAL storage_engine='InnoDb';

  • MySQL 5.6以降の場合、以下を使用します。

    SET GLOBAL default_storage_engine = 'InnoDB';

  • そして最後に、MySQLへの移行で提供されている指示に従っていることを確認してください。

参照


ほとんどの場合、ストレージエンジンを「InnoDB」として構成することを忘れています。次の答えは最も単純な答えであり、おそらくここでほとんどのユーザーの問題を解決します。ありがとう。
セザール

10

テーブルを作成または変更する前にこのクエリを実行してください。

SET @@global.innodb_large_prefix = 1;

これにより、キーの最大長が3072バイトに設定されます


3

このインデックスサイズの制限は、MySQLの64ビットビルドではより大きくなるようです。

私の開発データベースをダンプしてローカルVMWare virtにロードしようとして、この制限に達していました。最後に、リモートの開発サーバーが64ビットであり、32ビットの仮想サーバーを作成していることに気付きました。64ビット仮想マシンを作成したところ、データベースをローカルにロードできました。


2

このエラーを回避するには、元のデータベースの「長さ」の値を、構造を変更してサーバーにエクスポートすることにより、合計で約「1000」に変更します。:)


0

私は同じ問題に直面していました、それを解決するために以下のクエリを使用しました。

DBの作成中に、utf-8エンコーディングを使用できます

例えば。 create database my_db character set utf8 collate utf8mb4;

編集:(コメントからの提案を考慮して)utf8_binをutf8mb4に変更


2
これは私を正しい方向に向けました。私にとっては、照合をutf8_general_ci
Ian Newland

2
これは正しい方向ではありません。これを行わないでください!MySQL utf8はNOT utf8です。バグが発生した独自の形式であり、決して実現することはありませんでした。utf8mb4true utf8であり、適切なutf8サポートのために推奨されるデフォルトです。
ジェフリー

utf8mb4mysqlではなく正しいエンコーディングですutf8
alok

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