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

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

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

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

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



답변

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 열


답변

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.


답변

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

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


답변

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 수를 계산하는 다른 방법을 읽을 수 있습니다 .


답변

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

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

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


답변

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


답변

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