MySQL 例外:最大キー長は 767 バイトです

序文

最近、いくつかのテーブルを移行しましたが、767 例外が発生しました。移行前は sql_mode のみをチェックし、このパラメータを無視していました。その結果、いくつかのテーブルの作成に失敗しました。実際、解決策も非常に簡単です。パラメータを有効にして、逆輸入しますinnodb_large_prefixこのエラーは、文字列型の大きなフィールドでよく発生します。この記事では、この問題を簡単に記録します。

[42000][1071] 指定されたキーが長すぎます。キーの最大長は 767 バイトです

1. 767バイトの解釈

特定のテーブルの文字列フィールドが何バイトを占めているかを知るにはどうすればよいでしょうか? テーブルの文字セットと併せて確認する必要があります。

CREATE TABLE `test_index` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(800) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

上の表の文字タイプは utf8 です。表を参照することで、文字が占有できる最大スペースを決定できます。

show character set;
文字コード 説明 デフォルトの照合順序 マックスレン
ビッグ5 Big5 繁体字中国語 big5_chinese_ci 2
12月8日 12 月 西ヨーロッパ dec8_スウェーデン語_ci 1
CP850 DOS 西ヨーロッパ語 cp850_general_ci 1
hp8 HP西ヨーロッパ hp8_english_ci 1
こい8r KOI8-R Relcom ロシア語 koi8r_general_ci 1
ラテン語1 cp1252 西ヨーロッパ人 latin1_スウェーデン語_ci 1
ラテン語2 ISO 8859-2 中央ヨーロッパ latin2_general_ci 1
swe7 7ビットスウェーデン語 swe7_スウェーデン_ci 1
アスキー US ASCII ascii_general_ci 1
テスト EUC-JP 日本語 ujis_japanese_ci 3
たわごと シフトJIS日本語 sjis_japanese_ci 2
ヘブライ語 ISO 8859-8 ヘブライ語 hebrew_general_ci 1
tis620 TIS620 タイ語 tis620_thai_ci 1
ユークル EUC-KR 韓国語 euckr_korean_ci 2
koi8u KOI8-U ウクライナ語 koi8u_general_ci 1
GB2312 GB2312 簡体字中国語 gb2312_中国語_ci 2
ギリシャ語 ISO 8859-7 ギリシャ語 greek_general_ci 1
CP1250 Windows 中央ヨーロッパ cp1250_general_ci 1
gbk GBK 簡体字中国語 gbk_chinese_ci 2
ラテン5 ISO 8859-9 トルコ語 latin5_turkish_ci 1
armcii8 ARMSCII-8 アルメニア語 armcii8_general_ci 1
utf8 UTF-8 ユニコード utf8_general_ci 3
ucs2 UCS-2 ユニコード ucs2_general_ci 2
CP866 DOSロシア語 cp866_general_ci 1
keybc2 DOS カメニッキー チェコ語 - スロバキア語 keybcs2_general_ci 1
死んだ マック セントラル ヨーロッパ macce_general_ci 1
マクロマン マックウエストヨーロピアン マクロマン_ジェネラル_ci 1
CP852 DOS 中央ヨーロッパ cp852_general_ci 1
ラテン7 ISO 8859-13 バルト海 latin7_general_ci 1
utf8mb4 UTF-8 ユニコード utf8mb4_general_ci 4
CP1251 Windows キリル文字 cp1251_general_ci 1
edf16 UTF-16 ユニコード utf16_general_ci 4
utf16le UTF-16LE ユニコード utf16le_general_ci 4
CP1256 Windows アラビア語 cp1256_general_ci 1
cp1257 Windows Baltic cp1257_general_ci 1
utf32 UTF-32 Unicode utf32_general_ci 4
binary Binary pseudo charset binary 1
geostd8 GEOSTD8 Georgian geostd8_general_ci 1
cp932 SJIS for Windows Japanese cp932_japanese_ci 2
eucjpms UJIS for Windows Japanese eucjpms_japanese_ci 3
gb18030 China National Standard GB18030 gb18030_chinese_ci 4

例如 utf8 的 Maxlen = 3 表示一个字符最大占用 3 bytes。那么 varchar 类型小于 255 字符,就不会触发 767 异常。

2. 异常原因

为什么会有这个异常呢?其实该异常属于 MySQL Innodb 引擎的限制,例如一张表最多有 1017 个字段,一张表最大有 64 个二级索引一样,如果索引列的字符长度很大的话,二级索引占用的空间也会非常大,一个页面存储的索引字段减少,索引深度会更容易变深,增加 IO 次数,搜索的性能也不会理想。

If innodb_large_prefix is enabled (the default), the index key prefix limit is 3072 bytes for InnoDB tables that use the DYNAMIC or COMPRESSED row format. If innodb_large_prefix is disabled, the index key prefix limit is 767 bytes for tables of any row format.

Innodb 引擎的限制:14.23 InnoDB Limits

3. 5.7 和 8.0 版本的区别

在 5.7 版本中,对于使用 DYNAMIC 或 COMPRESSED 行格式的 InnoDB 表,索引前缀的限制为 767 bytes,如果开启 innodb_large_prefix 参数,限制阈值上调为 3072 bytes。

在 8.0 版本中,参数 innodb_large_prefix 被删除,索引前缀最大为 3072 bytes 不再有 767 bytes 的限制。

ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes

4. 版本 5.6 特殊情况

在 5.6 版本中 innodb_default_row_format = Compact 默认值,只有 DYNAMIC 和 COMPRESSED 行格式突破 767,所以 5.6 版本修改参数后,依然无法创建大于 767 字节的索引,此时可以去查表的行格式,大概率是行格式不支持:

select TABLE_SCHEMA, TABLE_NAME, ROW_FORMAT
from information_schema.TABLES where TABLE_NAME = '表名'

此时修改行格式可以解决:

alter table 表名 row_format=dynamic;

おすすめ

転載: blog.csdn.net/qq_42768234/article/details/131393039