MySQL错误:没有密钥长度的密钥规范

GSt*_*Sto 335 mysql sql mysql-error-1170

我有一个主键是一个varchar(255)的表.出现了一些情况,其中255个字符是不够的.我尝试将字段更改为文本,但是我收到以下错误:

BLOB/TEXT column 'message_id' used in key specification without a key length
Run Code Online (Sandbox Code Playgroud)

我怎样才能解决这个问题?

编辑:我还应该指出这个表有一个包含多列的复合主键.

OMG*_*ies 534

发生错误是因为MySQL只能索引BLOB或TEXT列的前N个字符.所以错误主要发生时,有一个领域/列类型TEXT或BLOB或那些属于TEXTBLOB类型,如TINYBLOB,MEDIUMBLOB,LONGBLOB,TINYTEXT,MEDIUMTEXT,和LONGTEXT您尝试使一个主键或索引.在完全BLOBTEXT没有长度值的情况下,MySQL无法保证列的唯一性,因为它具有可变和动态大小.因此,当使用BLOBTEXT键入索引时,必须提供N的值,以便MySQL可以确定密钥长度.但是,MySQL不支持TEXT或的密钥长度限制BLOB.TEXT(88)根本行不通.

当您尝试从中转换表列non-TEXTnon-BLOB键入诸如VARCHARENUM输入TEXTBLOB键入时,也会弹出错误,并且已将列定义为唯一约束或索引.Alter Table SQL命令将失败.

该问题的解决方案是从索引或唯一约束中删除TEXTor BLOB列或将另一个字段设置为主键.如果您不能这样做,并且想要对TEXTBLOB列设置限制,请尝试使用VARCHAR类型并对其设置长度限制.默认情况下,VARCHAR最多限制为255个字符,并且必须在声明后立即在括号内隐式指定其限制,即仅VARCHAR(200)将其限制为200个字符.

有时,即使您在表中没有使用TEXTBLOB相关类型,也可能出现错误1170.它发生在诸如将VARCHAR列指定为主键但错误地设置其长度或字符大小的情况下.VARCHAR最多只能接受256个字符,因此任何类似的操作VARCHAR(512)都会强制MySQL将数据类型自动转换VARCHAR(512)SMALLTEXT数据类型,如果该列用作主键或唯一或非唯一索引,则数据类型随后会因密钥长度错误1170而失败.要解决此问题,请指定小于256的数字作为VARCHAR字段的大小.

参考:MySQL错误1170(42000):BLOB/TEXT列在没有密钥长度的密钥规范中使用

  • http://dev.mysql.com/doc/refman/5.0/en/char.html"VARCHAR列中的值是可变长度字符串.在MySQL 5.0.3之前,长度可以指定为0到255之间的值, 5.0.3及更高版本中的0到65,535.MySQL 5.0.3及更高版本中VARCHAR的有效最大长度受最大行大小限制(65,535字节,在所有列之间共享) (13认同)
  • “在索引BLOB或TEXT列时,必须为索引指定前缀长度。” http://dev.mysql.com/doc/refman/5.6/en/column-indexes.html (2认同)
  • 我知道已经很晚了,但是**删除**“唯一键约束”解决了问题。我没有使用“TEXT”列作为“PK”,但我试图使其独一无二。我收到“1170 错误”,但是当我删除它时,错误就被删除了。 (2认同)
  • 貌似最后的链接失效了 (2认同)

Qua*_*noi 83

您应该定义TEXT要索引的列的哪个前导部分.

InnoDB768每个索引键有一个字节限制,你将无法创建一个比这更长的索引.

这样可以正常工作:

CREATE TABLE t_length (
      mydata TEXT NOT NULL,
      KEY ix_length_mydata (mydata(255)))
    ENGINE=InnoDB;
Run Code Online (Sandbox Code Playgroud)

请注意,密钥大小的最大值取决于列charset.它767是单字节字符集的字符LATIN1,只有255字符UTF8(MySQL仅用于每个字符BMP最多需要3字节)

如果您需要整列PRIMARY KEY,计算SHA1MD5散列并将其用作a PRIMARY KEY.


小智 59

您可以在alter table请求中指定密钥长度,例如:

alter table authors ADD UNIQUE(name_first(20), name_second(20));
Run Code Online (Sandbox Code Playgroud)

  • 这正是*我*需要解决同样的问题。谢谢! (2认同)
  • 你应该非常小心这种方法!这可能是最简单的解决方案,但在很多情况下并不是最好的解决方案.您的密钥由两列组成,列顺序很重要. (2认同)

MrD*_*MrD 21

MySQL的不允许索引的全部价值BLOB,TEXT而长VARCHAR列,因为它们含有可以是巨大的数据,并含蓄DB指数将是很大的,这意味着没有从索引中获益.

MySQL要求你定义要编入索引的前N个字符,其技巧是选择一个足够长的数字N来提供良好的选择性,但又足够短以节省空间.前缀应足够长,以使索引几乎与索引整列时的索引一样有用.

在我们进一步讨论之前,让我们定义一些重要术语 索引选择性总不同索引值与总行数之比.以下是测试表的一个示例:

+-----+-----------+
| id  | value     |
+-----+-----------+
| 1   | abc       |
| 2   | abd       |
| 3   | adg       |
+-----+-----------+
Run Code Online (Sandbox Code Playgroud)

如果我们只索引第一个字符(N = 1),那么索引表将如下表所示:

+---------------+-----------+
| indexedValue  | rows      |
+---------------+-----------+
| a             | 1,2,3     |
+---------------+-----------+
Run Code Online (Sandbox Code Playgroud)

在这种情况下,指数选择性等于IS = 1/3 = 0.33.

现在让我们看看如果我们将索引字符数增加到两个(N = 2)会发生什么.

+---------------+-----------+
| indexedValue  | rows      |
+---------------+-----------+
| ab             | 1,2      |
| ad             | 3        |
+---------------+-----------+
Run Code Online (Sandbox Code Playgroud)

在这种情况下,IS = 2/3 = 0.66这意味着我们增加了索引选择性,但我们也增加了索引的大小.诀窍是找到最小数量N,这将导致最大索引选择性.

您可以使用两种方法为数据库表进行计算.我将在这个数据库转储上进行演示.

假设我们想要将表employee中的列last_name添加到索引中,并且我们想要定义将产生最佳索引选择性的最小数量N.

首先让我们确定最常见的姓氏:

select count(*) as cnt, last_name 
from employees 
group by employees.last_name 
order by cnt

+-----+-------------+
| cnt | last_name   |
+-----+-------------+
| 226 | Baba        |
| 223 | Coorg       |
| 223 | Gelosh      |
| 222 | Farris      |
| 222 | Sudbeck     |
| 221 | Adachi      |
| 220 | Osgood      |
| 218 | Neiman      |
| 218 | Mandell     |
| 218 | Masada      |
| 217 | Boudaillier |
| 217 | Wendorf     |
| 216 | Pettis      |
| 216 | Solares     |
| 216 | Mahnke      |
+-----+-------------+
15 rows in set (0.64 sec)
Run Code Online (Sandbox Code Playgroud)

如您所见,Baba的姓氏是最常见的名字.现在我们将找到最常出现的last_name前缀,以五个字母的前缀开头.

+-----+--------+
| cnt | prefix |
+-----+--------+
| 794 | Schaa  |
| 758 | Mande  |
| 711 | Schwa  |
| 562 | Angel  |
| 561 | Gecse  |
| 555 | Delgr  |
| 550 | Berna  |
| 547 | Peter  |
| 543 | Cappe  |
| 539 | Stran  |
| 534 | Canna  |
| 485 | Georg  |
| 417 | Neima  |
| 398 | Petti  |
| 398 | Duclo  |
+-----+--------+
15 rows in set (0.55 sec)
Run Code Online (Sandbox Code Playgroud)

每个前缀都会出现更多,这意味着我们必须增加数字N,直到值与前一个示例中的值几乎相同.

这是N = 9的结果

select count(*) as cnt, left(last_name,9) as prefix 
from employees 
group by prefix 
order by cnt desc 
limit 0,15;

+-----+-----------+
| cnt | prefix    |
+-----+-----------+
| 336 | Schwartzb |
| 226 | Baba      |
| 223 | Coorg     |
| 223 | Gelosh    |
| 222 | Sudbeck   |
| 222 | Farris    |
| 221 | Adachi    |
| 220 | Osgood    |
| 218 | Mandell   |
| 218 | Neiman    |
| 218 | Masada    |
| 217 | Wendorf   |
| 217 | Boudailli |
| 216 | Cummings  |
| 216 | Pettis    |
+-----+-----------+
Run Code Online (Sandbox Code Playgroud)

这是N = 10的结果.

+-----+------------+
| cnt | prefix     |
+-----+------------+
| 226 | Baba       |
| 223 | Coorg      |
| 223 | Gelosh     |
| 222 | Sudbeck    |
| 222 | Farris     |
| 221 | Adachi     |
| 220 | Osgood     |
| 218 | Mandell    |
| 218 | Neiman     |
| 218 | Masada     |
| 217 | Wendorf    |
| 217 | Boudaillie |
| 216 | Cummings   |
| 216 | Pettis     |
| 216 | Solares    |
+-----+------------+
15 rows in set (0.56 sec)
Run Code Online (Sandbox Code Playgroud)

这是非常好的结果.这意味着我们可以在列last_name上创建索引,仅索引前10个字符.在表定义列last_name中定义为VARCHAR(16),这意味着每个条目我们已经保存了6个字节(如果姓氏中有UTF8字符,则保存更多字节).在这个表中有1637个不同的值乘以6个字节大约9KB,并想象如果我们的表包含数百万行,这个数字将如何增长.

您可以在MySQL的后期前缀索引中阅读其他计算N数的方法.

  • 尚未更新足够。我发现它比公认的答案更容易理解 (3认同)

ste*_*lth 15

向具有文本类型列的表添加索引时出现此错误。您需要声明要用于每种文本类型的大小数量。

将大小数量放在括号 ( ) 内

如果使用了太多字节,您可以在 varchar 的括号中声明一个大小以减少用于索引的数量。即使您为已经像 varchar(1000) 这样的类型声明了大小也是如此。您不需要像其他人所说的那样创建新表。

添加索引

alter table test add index index_name(col1(255),col2(255));
Run Code Online (Sandbox Code Playgroud)

添加唯一索引

alter table test add unique index_name(col1(255),col2(255));
Run Code Online (Sandbox Code Playgroud)


par*_*par 6

解决此问题的另一种极好方法是创建没有唯一约束的 TEXT 字段,并添加一个唯一的同级 VARCHAR 字段,该字段包含 TEXT 字段的摘要(MD5、SHA1 等)。当您插入或更新 TEXT 字段时,计算并存储整个 TEXT 字段的摘要,然后您就可以快速搜索整个 TEXT 字段(而不是某些前导部分)的唯一性约束。

  • MD5、SHA1 在非恶意数据上的分布应该是统一的——这就是散列的用途。 (2认同)

Abh*_*oel 6

alter table authors ADD UNIQUE(name_first(767), name_second(767));
Run Code Online (Sandbox Code Playgroud)

注意767是MySQL在处理blob / text索引时将索引列的最大字符数限制

参考:http : //dev.mysql.com/doc/refman/5.7/en/innodb-restrictions.html