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或那些属于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
or 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错误1170(42000):BLOB/TEXT列在没有密钥长度的密钥规范中使用
Qua*_*noi 83
您应该定义TEXT
要索引的列的哪个前导部分.
InnoDB
768
每个索引键有一个字节限制,你将无法创建一个比这更长的索引.
这样可以正常工作:
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
,计算SHA1
或MD5
散列并将其用作a PRIMARY KEY
.
小智 59
您可以在alter table请求中指定密钥长度,例如:
alter table authors ADD UNIQUE(name_first(20), name_second(20));
Run Code Online (Sandbox Code Playgroud)
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,并想象如果我们的表包含数百万行,这个数字将如何增长.
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)
解决此问题的另一种极好方法是创建没有唯一约束的 TEXT 字段,并添加一个唯一的同级 VARCHAR 字段,该字段包含 TEXT 字段的摘要(MD5、SHA1 等)。当您插入或更新 TEXT 字段时,计算并存储整个 TEXT 字段的摘要,然后您就可以快速搜索整个 TEXT 字段(而不是某些前导部分)的唯一性约束。
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
归档时间: |
|
查看次数: |
341063 次 |
最近记录: |