MySQL 오류 : 키 길이가없는 키 사양


363

varchar (255) 인 기본 키가있는 테이블이 있습니다. 255 자로 충분하지 않은 경우가 있습니다. 필드를 텍스트로 변경하려고 시도했지만 다음 오류가 발생합니다.

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

이 문제를 어떻게 해결할 수 있습니까?

편집 : 또한이 테이블에는 여러 열이있는 복합 기본 키가 있음을 지적해야합니다.


9
테이블에는 기본 키가 여러 개있을 수 없습니다. 복합 기본 키 (열이 두 개 이상 포함) 또는 여러 UNIQUE키가 있음을 의미합니까?
Quassnoi

1
제 경우에는 VARCHAR 대신 전자 메일 열에 TEXT 유형이 있습니다.
Kris

고유 한 영숫자에는 VARCHAR을 사용하십시오.
JWC 5 월

답변:


571

MySQL이 BLOB 또는 TEXT열의 첫 번째 N 문자 만 색인 할 수 있기 때문에 오류가 발생합니다 . 필드 / 열 유형이있는 경우 오류가 주로 발생 그래서 TEXTBLOB 나에 속하는 나 TEXT또는 BLOB같은 종류의 TINYBLOB, MEDIUMBLOB, LONGBLOB, TINYTEXT, MEDIUMTEXT, 및 LONGTEXT기본 키 또는 인덱스를 만들기 위해 노력하고있다. 전체 BLOB또는 TEXT길이 값이 없으면 MySQL은 가변적이고 동적 크기이므로 열의 고유성을 보장 할 수 없습니다. 따라서 BLOB또는 TEXT인덱스를 인덱스로 사용 하는 경우 MySQL이 키 길이를 결정할 수 있도록 N 값을 제공해야합니다. 그러나 MySQL은 TEXT또는 에서 키 길이 제한을 지원하지 않습니다 BLOB. TEXT(88)단순히 작동하지 않습니다.

당신이에서 테이블 열을 변환 할 때 오류가 나타납니다 non-TEXTnon-BLOB같은 입력 VARCHARENUMTEXTBLOB이미 고유 제한 조건 또는 인덱스로 정의 된 컬럼에 입력합니다. 테이블 변경 SQL 명령이 실패합니다.

이 문제에 대한 해결책 은 인덱스 또는 고유 제한 조건에서 TEXT또는 BLOB열 을 제거 하거나 다른 필드를 기본 키로 설정하는 것입니다. 그렇게 할 수없고 TEXT또는 BLOB열에 제한 을 설정하려면 VARCHARtype 을 사용 하고 길이 제한을 시도 하십시오. 기본적 VARCHAR으로 최대 255 자로 제한되며 선언 직후 괄호 안에 암시 적으로 제한을 지정해야합니다. 즉, VARCHAR(200)최대 200 자로 제한됩니다.

가끔, 당신이 사용하지 TEXT않거나 BLOB관련 유형을 테이블에, 오류 1170가 나타날 수도 있습니다. VARCHAR열을 기본 키로 지정 했지만 길이 또는 문자 크기를 잘못 설정 한 경우와 같은 상황에서 발생 합니다. VARCHAR는 최대 256 자까지만 허용하므로 VARCHAR(512)MySQL VARCHAR(512)SMALLTEXT데이터 유형 으로 자동 변환하도록 강제하는 것과 같은 것은 열이 기본 키 또는 고유 또는 고유하지 않은 인덱스로 사용되는 경우 키 길이에서 오류 1170으로 실패합니다. 이 문제를 해결하려면 VARCHAR필드 크기로 256보다 작은 그림을 지정하십시오 .

참조 : MySQL 오류 1170 (42000) : 키 길이없이 키 사양에 사용 된 BLOB / TEXT 열


13
dev.mysql.com/doc/refman/5.0/en/char.html "VARCHAR 열의 값은 가변 길이 문자열입니다. 길이는 MySQL 5.0.3 이전에는 0에서 255 사이, 0에서 65,535 사이의 값으로 지정할 수 있습니다. . "(모든 열에서 공유 65,535 바이트) 5.0.3에서 VARCHAR의 유효 최대 길이 5.0.3 이상 버전과 이후 최대 행 크기의 적용을받습니다
umassthrower

1
"MySQL은 BLOB 또는 TEXT 열의 첫 N 문자 만 색인 할 수 있습니다"라고 말하면 N의 값은 무엇입니까?
jameshfisher

2
"BLOB 또는 TEXT 열을 색인 할 때 색인의 접두사 길이를 지정해야합니다." dev.mysql.com/doc/refman/5.6/en/column-indexes.html
Vinicius Pinto

86

TEXT색인을 생성 할 열의 선행 부분을 정의해야합니다 .

InnoDB768인덱스 키당 바이트 수 제한이 있으며 그보다 긴 인덱스를 만들 수 없습니다.

이것은 잘 작동합니다 :

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.


정확히 내가 찾던 것. 감사!
Jonathon Hill

크기 (255)는 실제로 바이트 단위가 아닌 문자 단위입니까? UTF-8에 문자를 사용하는 것이 추가 이점없이 실제로 복잡 할 것이라고 생각할 수 있기 때문입니다.
Alexis Wilke

죄송합니다. 귀하의 질문에 따르지 않습니다. 문서에서 : 인덱스 키 접두사 길이 제한은 REDUNDANTor COMPACT행 형식 을 사용하는 InnoDB 테이블의 경우 767 바이트입니다 . 예를 들어, 당신은에 255 개 이상의 문자의 열 접두사 색인이 제한 히트 수 TEXT또는 VARCHARutf8mb3 문자 집합 및 각 문자에 대한 3 바이트의 최대 가정, 열을. REDUNDANT그리고 COMPACT이 대답이 주어진 시간에 사용할 수있는 유일한 형식이었다.
Quassnoi

62

다음과 같이 alter table 요청에서 키 길이를 지정할 수 있습니다.

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

1
이것은 정확하게이었다 내가 같은 문제를 해결하기 위해 필요합니다. 감사!
퀘스트 당 Aronsson

2
이 접근 방식에 매우주의해야합니다! 이것은 가장 쉬운 해결책 일 수 있지만 많은 상황에서 가장 좋은 해결책은 아닙니다. 키는 두 개의 열로 구성되며 열 순서는 중요합니다.
MrD

가장 좋은 답변은 여기입니다.
George Chalhoub

이렇게하면 내 문제가 해결됩니다. 대단히 감사합니다!
dellair

22

MySQL의 전체 값을 인덱싱하는 것을 허용하지 BLOB, TEXTVARCHAR열을가 거대 할 수 있습니다 포함하는 데이터 때문에, 그리고 암시 적으로 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과 같습니다.

인덱스 문자 수를 2로 늘리면 어떻게 될지 살펴 보자 (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 접두사를 5 자리 접두사로 시작합니다.

+-----+--------+
| 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가 있으며 테이블에 백만 개의 행이 포함되어 있으면이 숫자가 어떻게 증가하는지 상상해보십시오.

MySQL의접두사 색인에서 N 수를 계산하는 다른 방법을 읽을 수 있습니다 .


3
이것은 충분히 업데이트되지 않았습니다. 나는 받아 들여진 대답보다 이해 하기가 훨씬 쉽다는 것을 알았습니다.
Mawg는 Monica를 복원

10

텍스트 유형 열이있는 테이블에 색인을 추가 할 때이 오류가 발생했습니다. 각 텍스트 유형에 사용할 크기를 선언해야합니다.

크기를 괄호 안에 넣습니다 ()

너무 많은 바이트가 사용되는 경우 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));

가장 간단한 대답은 내가 믿었고 바로 나를 위해 일했습니다. 감사.
Matt Cremeens


4

이를 처리하는 또 다른 훌륭한 방법은 고유 제한 조건없이 TEXT 필드를 작성하고 TEXT 필드의 다이제스트 (MD5, SHA1 등)를 포함하는 형제 VARCHAR 필드를 추가하는 것입니다. TEXT 필드를 삽입하거나 업데이트 할 때 전체 TEXT 필드에 대한 요약을 계산하고 저장하면 빠르게 검색 할 수있는 전체 TEXT 필드 (일부 부분이 아닌)에 대해 고유 제한 조건이 있습니다.


1
MD5 (), SHA1 () 또는 UUID ()에 의해 생성 된 것과 같은 완전히 "랜덤"문자열도 매우 신중해야합니다. 당신이 그들과 함께 생성하는 각각의 새로운 값은 넓은 공간에 임의의 방식으로 분산되어 INSERT 및 일부 유형의 SELECT 쿼리를 느리게 할 수 있습니다.
MrD

2
악성이 아닌 데이터에 대한 MD5, SHA1의 분포는 균일해야합니다.
jb.

예를 들어 주시면 좋을 것입니다.
WebComer

3

기본 키로 긴 값이 없습니다. 성능이 저하 될 수 있습니다. mysql 매뉴얼 섹션 13.6.13 'InnoDB 성능 조정 및 문제 해결'을 참조하십시오.

대신, 대리 int 키를 기본 (auto_increment 포함)으로, loong 키를 보조 UNIQUE로 사용하십시오.


2

255자가 충분하지 않을 때 오버플로를 유지하려면 다른 varChar (255) 열 (기본값은 null이 아닌 빈 문자열)을 추가하고 두 열을 모두 사용하도록이 PK를 변경하십시오. 이것은 잘 설계된 데이터베이스 스키마처럼 들리지 않으므로 데이터 모델러가 더 표준화하기 위해 리팩토링하기 위해 가지고있는 것을 볼 것을 권장합니다.


2

문제에 대한 해결책은 CREATE TABLE명령문 UNIQUE ( problemtextfield(300) )에서 열 작성 정의 후에 제한 조건 을 추가하여 필드 key300문자 길이 를 지정하는 것 TEXT입니다. 그런 다음 필드 의 첫 300문자는 problemtextfield TEXT고유해야하며 그 이후의 차이점은 무시됩니다.


1

또한이 필드에 인덱스를 사용하려면 MyISAM 스토리지 엔진과 FULLTEXT 인덱스 유형을 사용해야합니다.


설명을 추가하고 문서에 대한 링크를 고려할 수 있습니다.
LeeGee

1

지금까지 아무도 언급하지 않았습니다 ... 4 바이트 utf8mb4로 이모티콘을 저장할 수도 있습니다 (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 (또는 이전 utf8의 경우 VARCHAR (1024))를 사용할 수 있습니다. innodb_large_prefix 옵션은 동작이 내장 MySQL 8이기 때문에 5.7.7부터 더 이상 사용되지 않습니다 (이 버전에서는 옵션이 제거됨).


0

열 유형을 색인 으로 varchar또는 integer색인 으로 변경해야 합니다.


설명을 추가하고 문서에 대한 링크를 고려할 수 있습니다.
LeeGee


-1

이런 식으로 사용

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

설명을 추가하고 문서에 대한 링크를 고려할 수 있습니다.
LeeGee
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.