Ошибка MySQL: спецификация ключа без ключа

У меня есть таблица с первичным ключом, который является varchar (255). Некоторые случаи возникли, когда 255 символов недостаточно. Я попытался изменить поле на текст, но я получаю следующую ошибку:

BLOB/TEXT column 'message_id' used in key specification without a key length

как я могу это исправить?

edit: Я должен также указать, что в этой таблице есть составной первичный ключ с несколькими столбцами.

Ответ 1

Ошибка возникает из-за того, что MySQL может индексировать только первые N символов столбца BLOB или TEXT. Таким образом, ошибка в основном происходит, когда существует тип поля/столбца 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, при этом столбец уже был определенные как уникальные ограничения или индекс. Ошибка команды SQL Alter Table.

Решение проблемы состоит в том, чтобы удалить столбец 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 1170 (42000): столбец BLOB/TEXT, используемый в спецификации ключа без длины ключа

Ответ 2

Вы должны определить, какую ведущую часть столбца 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.

Ответ 3

Вы можете указать длину ключа в запросе alter table, например:

alter table authors ADD UNIQUE(name_first(20), name_second(20));

Ответ 4

MySQL запрещает индексирование полного значения столбцов BLOB, TEXT и long VARCHAR, потому что данные, которые они содержат, могут быть огромными, а неявно индекс DB будет большим, что не означает выгоды от индекса.

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, которое приведет к максимальной селективности индекса.

Существует два подхода, которые вы можете выполнить для расчета таблицы базы данных. Я сделаю демонстрацию на этой дампе базы данных.

Предположим, мы хотим добавить столбец 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 байт, составляет около 9 КБ, и представьте, как это число будет расти, если наша таблица содержит миллион строк.

Вы можете прочитать другие способы вычисления числа N в моем сообщении Префиксные индексы в MySQL.

Ответ 5

alter table authors ADD UNIQUE(name_first(767), name_second(767));

ПРИМЕЧАНИЕ: 767 - это количество символов, до которого MySQL будет индексировать столбцы при работе с BLOB/текстовыми индексами.

Ссылка: http://dev.mysql.com/doc/refman/5.7/en/innodb-restrictions.html

Ответ 6

Не имеет длинных значений в качестве первичного ключа. Это разрушит вашу работу. См. Руководство по mysql, раздел 13.6.13 "Настройка производительности и устранение неполадок InnoDB".

Вместо этого, иметь суррогатный ключ int как первичный (с auto_increment), а ваш ключ loong как вторичный UNIQUE.

Ответ 7

Еще один отличный способ справиться с этим - создать поле TEXT без уникального ограничения и добавить уникальное поле VARCHAR для сиблинга, которое содержит дайджест (MD5, SHA1 и т.д.) поля TEXT. Вычислите и сохраните дайджест во всем поле ТЕКСТ, когда вы вставляете или обновляете поле ТЕКСТ, тогда у вас есть ограничение уникальности во всем поле ТЕКСТ (а не какая-то ведущая часть), которую можно быстро найти.

Ответ 8

Добавьте еще один столбец varChar (255) (по умолчанию как пустая строка не null), чтобы удерживать переполнение, когда 255 символов недостаточно, и измените этот PK на использование обоих столбцов. Однако это не похоже на хорошо спроектированную схему базы данных, и я бы рекомендовал получить модель данных данных для просмотра того, что у вас есть, с целью рефакторинга для большей нормализации.

Ответ 9

Кроме того, если вы хотите использовать индекс в этом поле, вы должны использовать механизм хранения MyISAM и индексный тип FULLTEXT.

Ответ 10

Решение проблемы заключается в том, что в вашем операторе CREATE TABLE вы можете добавить ограничение UNIQUE ( problemtextfield(300) ) после того, как столбец создаст определения, чтобы указать длину key символов 300 для поля TEXT, для пример. Тогда первые 300 символы поля problemtextfield TEXT должны быть уникальными, и любые различия после этого будут проигнорированы.

Ответ 11

Используйте это

@Id
@Column(name = "userEmailId", length=100)
private String userEmailId;

Ответ 12

Вы должны изменить тип столбца на varchar или integer для индексации.

Ответ 13

Перейдите в edit table mysql → измените тип столбца на varchar(45).

Ответ 14

Пока никто не упоминал об этом... с utf8mb4, который является 4-байтовым и может также хранить смайлики (мы никогда не должны больше использовать 3-байтовый utf8), и мы можем избежать ошибок, таких как Incorrect string value: \xF0\x9F\x98\... мы не должны использовать типичные VARCHAR (255), а VARCHAR (191), так как в случае utf8mb4 и VARCHAR (255) та же часть данных хранится вне страницы, и вы не можете создать индекс для столбца VARCHAR (255), но и для VARCHAR ( 191) можно. Это связано с тем, что максимальный размер индексированного столбца составляет 767 байт для ROW_FORMAT = COMPACT или ROW_FORMAT = REDUNDANT.

Для более новых форматов строк ROW_FORMAT = DYNAMIC или ROW_FORMAT = COMPRESSED (для которого требуется более новый формат файла innodb_file_format = Barracuda not old Antelope) максимальный размер индексированного столбца равен 3072. Он доступен с MySQL> = 5.6.3, когда innodb_large_prefix = 1 (по умолчанию отключено для MySQL <= 5.7.6 и включен по умолчанию для MySQL> = 5.7.7). Поэтому в этом случае мы можем использовать VARCHAR (768) для utf8mb4 (или VARCHAR (1024) для старого utf8) для индексированного столбца. Опция innodb_large_prefix устарела с 5.7.7, потому что ее поведение встроено в MySQL 8 (в этой версии опция удалена).

Ответ 15

Я получил эту ошибку при добавлении индекса в таблицу со столбцами текстового типа. Вам необходимо указать размер, который вы хотите использовать для каждого типа текста.

Укажите размер в скобках()

Если используется слишком много байтов, вы можете объявить размер в скобках для 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));