执行以下命令时:

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

我得到了这个错误信息:

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

columnn1和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

当前回答

对于这个问题,我自己的解决方案比降低表的VARCHAR大小更简单,也更安全。

情况:CentOS 7服务器运行Plesk Obsidian 18.0.37和MariaDB 5.5。我试图从运行MariaDB 10.1的服务器导入MySQL转储。

解决方案:从MariaDB 5.5升级到10.6。

这些步骤大致基于以下指南和以下指南:

mysqldump -u admin -p`cat /etc/psa/.psa.shadow` --all-databases --routines --triggers > /root/all-databases.sql systemctl stop mariadb cp -a /var/lib/mysql/ /var/lib/mysql_backup Configure MariaDB repositories according to the official guide Make sure you meet Plesk's minimum version requirements detailed here yum install MariaDB-client MariaDB-server MariaDB-compat MariaDB-shared systemctl start mariadb In my case, the server failed to start here with an error: "Can't start server: Bind on TCP/IP port. Got error: 22: Invalid argument". The fix was to replace bind-address as follows in /etc/my.cnf and re-run the command: [mysqld] # OLD (broken) #bind-address = ::ffff:127.0.0.1 # NEW bind-address = 127.0.0.1 MYSQL_PWD=`cat /etc/psa/.psa.shadow` mysql_upgrade -uadmin plesk sbin packagemng -sdf rm -f /etc/init.d/mysql systemctl daemon-reload

其他回答

我认为varchar(20)只需要21个字节,而varchar(500)只需要 需要501字节。所以总字节数是522,小于767。那么,为什么 我收到错误信息了吗?

UTF8每个字符需要3个字节来存储字符串,因此在您的情况下,20 +500字符= 20*3+500*3 = 1560字节,这超过了允许的767字节。

UTF8的限制是767/3 = 255个字符,对于每个字符使用4个字节的UTF8mb4,它是767/4 = 191个字符。


如果您需要使用比限制更长的列,有两种解决方案:

Use "cheaper" encoding (the one that requires less bytes per character) In my case, I needed to add Unique index on column containing SEO string of article, as I use only [A-z0-9\-] characters for SEO, I used latin1_general_ci which uses only one byte per character and so column can have 767 bytes length. Create hash from your column and use unique index only on that The other option for me was to create another column which would store hash of SEO, this column would have UNIQUE key to ensure SEO values are unique. I would also add KEY index to original SEO column to speed up look up.

将抱怨索引字段的CHARSET更改为“latin1” 例如:ALTER TABLE tbl CHANGE myfield varchar(600) CHARACTER SET latin1 DEFAULT NULL Latin1为一个字符使用一个字节,而不是四个

在我的例子中,我在使用linux重定向输出/输入字符备份数据库时遇到了这个问题。因此,我按照下面的描述更改语法。PS:使用linux或mac终端。

备份(没有>重定向)

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

恢复(不带< redirect)

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

错误“指定的键太长;最大密钥长度是767字节。

这个问题

MySQL中有最大键长度限制。

InnoDB -最大密钥长度为1536字节(8kb页面大小)和768字节(4kb页面大小)(来源:Dev.MySQL.com) MyISAM -最大密钥长度是1000字节(来源Dev.MySQL.com)。

这些都是以字节为单位计算的!因此,一个UTF-8字符可能需要一个以上的字节才能存储到密钥中。

因此,你只有两个直接的解决方案:

只索引文本类型的前n个字符。 创建一个全文搜索-所有内容都可以在文本中搜索,以一种类似ElasticSearch的方式

索引文本类型的前N个字符

如果您正在创建一个表,请使用以下语法来索引某些字段的前255个字符:KEY sometextkey (SomeText(255))。像这样:

CREATE TABLE `MyTable` (
    `id` int(11) NOT NULL auto_increment,
    `SomeText` TEXT NOT NULL,
    PRIMARY KEY  (`id`),
    KEY `sometextkey` (`SomeText`(255))
);

如果你已经有了这个表,那么你可以用add unique (ConfigValue(20));为一个字段添加一个唯一键。像这样:

ALTER TABLE
MyTable
ADD UNIQUE(`ConfigValue`(20));

如果字段名不是保留的MySQL关键字,则在字段名周围不需要反引号(' ' ')。

创建全文搜索

全文搜索将允许您搜索文本字段的全部值。如果你使用自然语言模式,它会进行全词匹配,如果你使用其他模式之一,它会进行部分词匹配。查看更多关于全文本的选项:Dev.MySQL.com

创建您的文本表,并添加全文索引…

ALTER TABLE
        MyTable
ADD FULLTEXT INDEX
        `SomeTextKey` (`SomeTextField` DESC);

然后像这样搜索你的桌子……

SELECT
        MyTable.id, MyTable.Title,
MATCH
        (MyTable.Text)
AGAINST
        ('foobar' IN NATURAL LANGUAGE MODE) AS score
FROM
        MyTable
HAVING
        score > 0
ORDER BY
        score DESC;

更改排序规则。您可以使用支持几乎所有功能的utf8_general_ci