我有一个主键是varchar(255)的表。出现了一些情况,其中255个字符是不够的。我尝试将字段更改为文本,但我收到以下错误:
BLOB/TEXT column 'message_id' used in key specification without a key length
我该如何解决这个问题?
编辑:我还应该指出这个表有一个包含多列的复合主键。
答案 0 :(得分:505)
发生错误是因为MySQL只能索引BLOB或TEXT
列的前N个字符。因此,如果字段/列类型为TEXT
或BLOB,或者属于TEXT
或BLOB
类型,例如TINYBLOB
,MEDIUMBLOB
,则主要发生错误您尝试制作主键或索引的LONGBLOB
,TINYTEXT
,MEDIUMTEXT
和LONGTEXT
。对于没有长度值的完整BLOB
或TEXT
,MySQL无法保证列的唯一性,因为它具有可变和动态大小。因此,当使用BLOB
或TEXT
类型作为索引时,必须提供N的值,以便MySQL可以确定密钥长度。但是,MySQL不支持TEXT
或BLOB
的密钥长度限制。 TEXT(88)
根本行不通。
当您尝试将表格列从non-TEXT
和non-BLOB
类型(例如VARCHAR
和ENUM
转换为TEXT
时,也会弹出错误BLOB
类型,列已被定义为唯一约束或索引。 Alter Table SQL命令将失败。
问题的解决方案是从索引或唯一约束中删除TEXT
或BLOB
列,或将另一个字段设置为主键。如果您不能这样做,并希望对TEXT
或BLOB
列设置限制,请尝试使用VARCHAR
类型并对其设置长度限制。默认情况下,VARCHAR
限制为最多255个字符,并且必须在声明后立即在括号内隐式指定其限制,即VARCHAR(200)
将其限制为仅200个字符。
有时,即使您未在表格中使用TEXT
或BLOB
相关类型,也可能会出现错误1170。它发生在诸如将VARCHAR
列指定为主键但错误地设置其长度或字符大小的情况下。 VARCHAR
最多只能接受256个字符,因此VARCHAR(512)
等任何内容都会强制MySQL将VARCHAR(512)
自动转换为SMALLTEXT
数据类型,该数据类型随后会因错误1170而失败如果列用作主键或唯一或非唯一索引,则为密钥长度。要解决此问题,请指定小于256的数字作为VARCHAR
字段的大小。
参考:MySQL Error 1170 (42000): BLOB/TEXT Column Used in Key Specification Without a Key Length
答案 1 :(得分:76)
您应该定义要编入索引的TEXT
列的哪个前导部分。
InnoDB
每个索引键限制768
个字节,您将无法创建超过该索引的索引。
这样可以正常工作:
CREATE TABLE t_length (
mydata TEXT NOT NULL,
KEY ix_length_mydata (mydata(255)))
ENGINE=InnoDB;
请注意,密钥大小的最大值取决于列字符集。对于767
这样的单字节字符集,LATIN1
字符为255
只有UTF8
字符,MySQL
仅使用BMP
,最多需要3
每个字符PRIMARY KEY
个字节)
如果您需要将整个列设为SHA1
,请计算MD5
或PRIMARY KEY
哈希并将其用作{{1}}。
答案 2 :(得分:55)
您可以在alter table请求中指定密钥长度,例如:
alter table authors ADD UNIQUE(name_first(20), name_second(20));
答案 3 :(得分:19)
MySQL不允许索引BLOB
,TEXT
和长VARCHAR
列的完整值,因为它们包含的数据可能很大,并且隐含的数据库索引会很大,这意味着索引没有任何好处
MySQL要求您定义要编入索引的前N个字符,其诀窍是选择一个足够长的数字N来提供良好的选择性,但要足够短以节省空间。前缀应足够长,以使索引几乎与索引整列时的索引一样有用。
在我们进一步讨论之前,让我们定义一些重要的术语。 索引选择性是总不同索引值与总行数的比率。以下是测试表的一个示例:
+-----+-----------+
| id | value |
+-----+-----------+
| 1 | abc |
| 2 | abd |
| 3 | adg |
+-----+-----------+
如果我们只索引第一个字符(N = 1),那么索引表将如下表所示:
+---------------+-----------+
| indexedValue | rows |
+---------------+-----------+
| a | 1,2,3 |
+---------------+-----------+
在这种情况下,指数选择性等于IS = 1/3 = 0.33。
现在让我们看看如果我们将索引字符数增加到两个(N = 2)会发生什么。
+---------------+-----------+
| indexedValue | rows |
+---------------+-----------+
| ab | 1,2 |
| ad | 3 |
+---------------+-----------+
在这种情况下,IS = 2/3 = 0.66这意味着我们增加了索引选择性,但我们也增加了索引的大小。诀窍是找到最小数量N,这将导致最大索引选择性。
您可以使用两种方法对数据库表进行计算。我将在this database dump上进行演示。
假设我们要将表 employees 中的列 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)
如您所见,姓氏 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)
每个前缀出现的次数要多得多,这意味着我们必须增加数字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 |
+-----+-----------+
以下是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)
这是非常好的结果。这意味着我们可以在列last_name
上建立索引,仅索引前10个字符。在表定义列last_name
中定义为VARCHAR(16)
,这意味着每个条目我们已经保存了6个字节(如果姓氏中有UTF8字符,则保存更多字节)。在这个表中有1637个不同的值乘以6个字节大约9KB,并想象如果我们的表包含数百万行,这个数字将如何增长。
您可以在我的帖子Prefixed indexes in MySQL中阅读其他计算 N 数量的方法。
答案 4 :(得分:6)
alter table authors ADD UNIQUE(name_first(767), name_second(767));
注意: 767 是在处理blob /文本索引时MySQL将索引列的字符数限制
参考:http://dev.mysql.com/doc/refman/5.7/en/innodb-restrictions.html
答案 5 :(得分:3)
不要将长值作为主键。这会破坏你的表现。请参阅mysql手册,第13.6.13节“InnoDB性能调整和故障排除”。
相反,将一个代理int键作为主键(使用auto_increment),并将loong键作为辅助UNIQUE。
答案 6 :(得分:2)
另一个处理此问题的好方法是创建没有唯一约束的TEXT字段,并添加一个唯一的兄弟VARCHAR字段,该字段包含TEXT字段的摘要(MD5,SHA1等)。当您插入或更新TEXT字段时,在整个TEXT字段上计算并存储摘要,然后您对可以快速搜索的整个TEXT字段(而不是某些前导部分)具有唯一性约束。
答案 7 :(得分:1)
添加另一个varChar(255)列(默认为空字符串not null)以在255个字符不足时保持溢出,并将此PK更改为使用两个列。这听起来并不像一个设计良好的数据库模式,我建议让数据建模人员查看你所拥有的内容,然后重构它以进行更多规范化。
答案 8 :(得分:0)
如果您的数据类型是 TEXT - 您必须将其更改为 VARCHAR
方案一:查询
ALTER TABLE table_name MODIFY COLUMN col_name datatype;
ALTER TABLE my_table MODIFY COLUMN my_col VARCHAR(255);
答案 9 :(得分:0)
删除该表,然后再次运行Spring Project。 这可能会有所帮助。 有时您要覆盖foreignKey。
答案 10 :(得分:0)
我知道已经很晚了,但是移除 Unique Key
约束解决了该问题。我没有将TEXT
或LONGTEXT
列用作PK,但是我试图使其成为唯一。我得到了1170 error
,但是当我删除UK
时,错误也被删除了。
我不完全理解为什么。
答案 11 :(得分:0)
向带有文本类型列的表添加索引时出现此错误。您需要声明每种文本类型要使用的大小量。
将尺寸大小放入括号()
如果使用了太多字节,则可以在括号中为varchar声明一个大小,以减少用于索引的数量。即使您为已经像varchar(1000)这样的类型声明了大小,也是如此。您无需像其他人一样创建新表。
添加索引
alter table test add index index_name(col1(255),col2(255));
添加唯一索引
alter table test add unique index_name(col1(255),col2(255));
答案 12 :(得分:0)
到目前为止,没有人提到它... utf8mb4是4字节,还可以存储图释(我们永远不应该再使用3字节utf8),并且我们可以避免出现类似Incorrect string value: \xF0\x9F\x98\...
的错误,我们不应该使用典型的 VARCHAR(255),而不是 VARCHAR(191),因为在utf8mb4和VARCHAR(255)的情况下,同一部分数据存储在页面外,因此您无法为列创建索引VARCHAR(255),但可以使用VARCHAR(191)。这是因为ROW_FORMAT = COMPACT或ROW_FORMAT = REDUNDANT的最大索引列大小为767个字节。
对于较新的行格式ROW_FORMAT = DYNAMIC或ROW_FORMAT = COMPRESSED(需要较新的文件格式innodb_file_format = Barracuda而不是较旧的Antelope),最大索引列大小为3072。当innodb_large_prefix = 1(禁用)时,MySQL> = 5.6.3可用。默认情况下,对于MySQL <= 5.7.6,默认情况下启用,对于MySQL> = 5.7.7)。因此,在这种情况下,我们可以将VARCHAR(768)用于utf8mb4(或将VARCHAR(1024)用于旧的utf8)用于索引列。从5.7.7版本开始不推荐使用innodb_large_prefix选项,因为它的行为是内置的MySQL 8(在此版本中,该选项已删除)。
答案 13 :(得分:0)
转到mysql edit table
->将列类型更改为varchar(45)
。
答案 14 :(得分:0)
您必须将列类型更改为varchar
或integer
才能建立索引。
答案 15 :(得分:0)
像这样使用
@Id
@Column(name = "userEmailId", length=100)
private String userEmailId;
答案 16 :(得分:0)
问题的解决方案是,在CREATE TABLE
语句中,您可以在列创建定义后添加约束UNIQUE ( problemtextfield(300) )
,以指定key
个300
个字符的长度例如,对于TEXT
字段。然后,300
problemtextfield
字段的第一个TEXT
字符必须是唯一的,之后的任何差异都将被忽略。
答案 17 :(得分:0)
此外,如果要在此字段中使用索引,则应使用MyISAM存储引擎和FULLTEXT索引类型。