以下内容对我来说非常合理:
CREATE TABLE `mydb`.`Temp` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`x` VARCHAR ( 300 ) NOT NULL ,
`id_foo` INT NULL DEFAULT NULL,
FOREIGN KEY ( `id_foo`) REFERENCES `Foo` (`id`) ON DELETE CASCADE ,
INDEX (`id_foo`),
INDEX (`x`),
UNIQUE (`id_foo`, `x`)
) ENGINE = INNODB;
使用MySQL会出现错误
#1071 - Specified key was too long; max key length is 767 bytes
这似乎是错误的,因为整行是309字节:小于767,甚至不是一半。发生了什么事?
答案 0 :(得分:6)
根据MYSQL Documantation:http://dev.mysql.com/doc/refman/5.0/en/create-index.html
MySQL对用于在列上定义索引的空间量有不同的限制
此外,这些列的数据类型很重要 - 对于VARCHAR,它是3x
因此,VARCHAR(300)上的索引就像在表中一样,将占用900个大于767字节的字节,即最大密钥长度。
编辑:显然这是不是 MySQL的错误,但MySQL中的 UTF8 最多支持3个字节。此外,引入4字节utf8字符集(WL#1213)最大可能密钥长度从255更改为191 字符(191 * 4 + 2 = 766,其中2个字节保持长度)。从MySQL 5.5或更高版本开始,所有-utf,-utf8mb4,-utf16,-utf32都会受此影响。
答案 1 :(得分:2)
尝试确定该指数需要多长时间才能保持有效:
SELECT COUNT(DISTINCT(`x`)) as n_unique,
COUNT(DISTINCT(LEFT(`x`,200))) as n_100,
COUNT(DISTINCT(LEFT(`x`,150))) as n_150,
COUNT(DISTINCT(LEFT(`x`,100))) as n_100,
COUNT(DISTINCT(LEFT(`x`,50))) as n_50,
COUNT(DISTINCT(LEFT(`x`,25))) as n_25,
COUNT(DISTINCT(LEFT(`x`,10))) as n_10
FROM Temp;
将每个n_结果除以n_unique将为您提供百分比覆盖率。一旦你有了这个,你就可以用较少数量的角色获得不错的覆盖率。
ALTER TABLE Temp ADD index x_improved(20)
其中20实际上是上面给出的不同变量的n_个数。
答案 2 :(得分:0)
这是你的INDEX (x)
问题。如果VARCHAR更短,它就可以工作。
答案 3 :(得分:0)
您使用的字符集是什么?
基于该错误,您似乎使用的是多字节字符集,可能是utf8,每个字符保留3个字节。因此,utf8中的varchar(300)会产生900字节的密钥长度,超过了innodb的767限制。
要使用这些索引创建表,您需要使用不同的字符集,或缩短列的长度。如果您只是索引x,我建议只索引该列的前255个字符,但给定您的唯一索引包含x该解决方案不可行,因为如果它们匹配前255个字符,它会拒绝重复值,即使它们在最后45个字符中有所不同。
以下是一些可行的示例:
-- shorten x to 255 characters
CREATE TABLE `mydb`.`Temp` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`x` VARCHAR ( 255 ) NOT NULL ,
`id_foo` INT NULL DEFAULT NULL,
FOREIGN KEY ( `id_foo`) REFERENCES `Foo` (`id`) ON DELETE CASCADE ,
INDEX (`id_foo`),
INDEX (`x`),
UNIQUE (`id_foo`, `x`)
) ENGINE = INNODB;
-- use single-byte character set
CREATE TABLE `mydb`.`Temp` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`x` VARCHAR ( 300 ) NOT NULL ,
`id_foo` INT NULL DEFAULT NULL,
FOREIGN KEY ( `id_foo`) REFERENCES `Foo` (`id`) ON DELETE CASCADE ,
INDEX (`id_foo`),
INDEX (`x`),
UNIQUE (`id_foo`, `x`)
) ENGINE = INNODB DEFAULT CHARSET LATIN1;