# 1071-지정된 키가 너무 깁니다. 최대 키 길이는 1000 바이트입니다.


102

이 제목에 대한 질문은 이전에 답변 된 적이 있지만 계속 읽으십시오. 게시하기 전에이 오류에 대한 다른 모든 질문 / 답변을 철저히 읽었습니다.

다음 쿼리에 대해 위의 오류가 발생합니다.

CREATE TABLE IF NOT EXISTS `pds_core_menu_items` (
  `menu_id` varchar(32) NOT NULL,
  `parent_menu_id` int(32) unsigned DEFAULT NULL,
  `menu_name` varchar(255) DEFAULT NULL,
  `menu_link` varchar(255) DEFAULT NULL,
  `plugin` varchar(255) DEFAULT NULL,
  `menu_type` int(1) DEFAULT NULL,
  `extend` varchar(255) DEFAULT NULL,
  `new_window` int(1) DEFAULT NULL,
  `rank` int(100) DEFAULT NULL,
  `hide` int(1) DEFAULT NULL,
  `template_id` int(32) unsigned DEFAULT NULL,
  `alias` varchar(255) DEFAULT NULL,
  `layout` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`menu_id`),
  KEY `index` (`parent_menu_id`,`menu_link`,`plugin`,`alias`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

아무도 왜 그것을 고치는 방법을 알고 있습니까? 문제는이 동일한 쿼리가 내 로컬 컴퓨터에서 완벽하게 작동하고 이전 호스트에서도 잘 작동한다는 것입니다. Btw. 그것은 성숙한 프로젝트 인 phpdevshell에서 나왔습니다. 그래서 저는이 사람들이 그들이 무엇을하고 있는지 알고 있다고 생각합니다.

단서 감사합니다.

phpMyAdmin을 사용하고 있습니다.

답변:


170

@Devart가 말했듯이 인덱스의 총 길이가 너무 깁니다.

짧은 대답은 인덱스가 매우 부피가 크고 비효율적이기 때문에 긴 VARCHAR 열을 인덱싱해서는 안된다는 것입니다.

가장 좋은 방법은 접두사 인덱스 를 사용 하여 데이터의 왼쪽 부분 문자열 만 인덱싱하는 것입니다. 어쨌든 대부분의 데이터는 255 자보다 훨씬 짧습니다.

인덱스를 정의 할 때 열당 접두사 길이를 선언 할 수 있습니다. 예를 들면 :

...
KEY `index` (`parent_menu_id`,`menu_link`(50),`plugin`(50),`alias`(50))
...

그러나 주어진 열에 가장 적합한 접두사 길이는 무엇입니까? 알아내는 방법은 다음과 같습니다.

SELECT
 ROUND(SUM(LENGTH(`menu_link`)<10)*100/COUNT(`menu_link`),2) AS pct_length_10,
 ROUND(SUM(LENGTH(`menu_link`)<20)*100/COUNT(`menu_link`),2) AS pct_length_20,
 ROUND(SUM(LENGTH(`menu_link`)<50)*100/COUNT(`menu_link`),2) AS pct_length_50,
 ROUND(SUM(LENGTH(`menu_link`)<100)*100/COUNT(`menu_link`),2) AS pct_length_100
FROM `pds_core_menu_items`;

menu_link열에 주어진 문자열 길이 이하의 행 비율을 알려줍니다 . 다음과 같은 출력이 표시 될 수 있습니다.

+---------------+---------------+---------------+----------------+
| pct_length_10 | pct_length_20 | pct_length_50 | pct_length_100 |
+---------------+---------------+---------------+----------------+
|         21.78 |         80.20 |        100.00 |         100.00 |
+---------------+---------------+---------------+----------------+

이것은 문자열의 80 %가 20 자 미만이고 모든 문자열이 50 자 미만임을 알려줍니다. 따라서 접두사 길이 50 ​​이상을 인덱싱 할 필요가 없으며 255 자 전체 길이를 인덱싱 할 필요가 없습니다.

추신 : INT(1)INT(32)데이터 유형은 MySQL에 대한 또 다른 오해를 나타냅니다. 숫자 인수는 열에 허용되는 값의 범위 또는 스토리지와 관련이 없습니다. INT항상 4 바이트이며 -2147483648에서 2147483647까지의 값을 항상 허용합니다. 숫자 인수는 표시 중 패딩 값에 관한 것이며 ZEROFILL옵션 을 사용하지 않는 한 효과가 없습니다 .


17
자세한 설명을 해주셔서 감사합니다. 문제를 해결하는 것 외에도 가치있는 것을 배웠습니다.
CodeVirtuoso

실제로 인덱스를 설정해야하는 길이를 찾는 데 매우 유용한 쿼리입니다. 인덱스에 가장 적합한 길이를 결정하기 위해 이것을 여러 번 사용했습니다. 공유 해주셔서 감사합니다!
Niraj Kumar

1
문자열이 실제로 얼마나 긴지 측정하는 편리한 쿼리에는 미묘한 버그가 있습니다. 문자열이 모두 존재한다고 가정합니다. 즉, 그들이 모두 거기에 있다는 것입니다. 일부가 null이면 계산을 버리고 짧은 문자열을 과소보고합니다. count (*) 대신 count ([field_name])를 사용하려고합니다.
D Mac

첫 번째 "접두사"색인 이상을 사용하지 않습니다.
Rick James 19 년

28

이 오류는 인덱스 길이가 index1000 바이트 이상 임을 의미합니다 . MySQL 및 스토리지 엔진에는 이러한 제한이있을 수 있습니다. MySQL 5.5에서 비슷한 오류가 발생했습니다- '지정된 키가 너무 깁니다. 이 스크립트를 실행할 때 최대 키 길이는 3072 바이트입니다.

CREATE TABLE IF NOT EXISTS test_table1 (
  column1 varchar(500) NOT NULL,
  column2 varchar(500) NOT NULL,
  column3 varchar(500) NOT NULL,
  column4 varchar(500) NOT NULL,
  column5 varchar(500) NOT NULL,
  column6 varchar(500) NOT NULL,
  KEY `index` (column1, column2, column3, column4, column5, column6)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

UTF8은 다중 바이트이며 키 길이는 500 * 3 * 6 = 9000 바이트와 같이 계산됩니다.

그러나 다음 쿼리가 작동합니다!

CREATE TABLE IF NOT EXISTS test_table1 (
  column1 varchar(500) NOT NULL,
  column2 varchar(500) NOT NULL,
  column3 varchar(500) NOT NULL,
  column4 varchar(500) NOT NULL,
  column5 varchar(500) NOT NULL,
  column6 varchar(500) NOT NULL,
  KEY `index` (column1, column2, column3, column4, column5, column6)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

... CHARSET = latin1을 사용했기 때문에이 경우 키 길이는 500 * 6 = 3000 바이트입니다.


7
답장을 보내 주셔서 감사합니다. 작동하지만 utf8 charset을 포기해야합니다. 이 제한을 어떻게 든 극복 할 수 있습니까 (전체 서버 액세스 권한이 있음), 정당한 이유가 있습니까?
CodeVirtuoso

4
이것은 끔찍한 조언입니다. 문자셋이 무엇인지, 그리고 이것이 앞으로 어떻게 주요 문제를 일으킬 지 알아보십시오. 혼합 문자 집합 데이터베이스는 조인 또는 하위 선택을 사용할 때 문제를 일으킬뿐만 아니라 데이터를 정규화되지 않은 형식으로 저장하며 나중에 수정하기가 거의 불가능할 수 있습니다.
Geoffrey

17

이 문제가 발생하여 다음과 같이 해결했습니다.

원인

여기에서 확인할 수있는 MyISAM, UTF8 문자 집합 및 인덱스와 관련된 MySQL의 알려진 버그가 있습니다.

해결

  • MySQL이 InnoDB 스토리지 엔진으로 구성되어 있는지 확인하십시오.

  • 새 테이블이 항상 적절하게 생성되도록 기본적으로 사용되는 스토리지 엔진을 변경합니다.

    set GLOBAL storage_engine='InnoDb';

  • MySQL 5.6 이상의 경우 다음을 사용하십시오.

    SET GLOBAL default_storage_engine = 'InnoDB';

  • 마지막으로 Migrating to MySQL에 제공된 지침을 따르고 있는지 확인하십시오 .

참고


대부분의 경우 스토리지 엔진을 'InnoDB'로 구성하는 것을 잊습니다. 다음 답변은 가장 간단한 답변이며 아마도 여기에있는 대부분의 사용자에게 문제를 해결할 것입니다. 감사.
Frederiko Cesar

10

테이블을 만들거나 변경하기 전에이 쿼리를 실행하십시오.

SET @@global.innodb_large_prefix = 1;

이것은 최대 키 길이를 3072 바이트로 설정합니다.


3

이 인덱스 크기 제한은 MySQL의 64 비트 빌드에서 더 큰 것으로 보입니다.

이 제한에 부딪 히고 dev 데이터베이스를 덤프하고 로컬 VMWare virt에로드하려고했습니다. 마지막으로 원격 개발 서버가 64 비트라는 것을 깨달았고 32 비트의 virt를 만들었습니다. 방금 64 비트 virt를 만들었고 데이터베이스를 로컬로로드 할 수있었습니다.


2

원래 데이터베이스의 "길이"값을 구조를 변경하여 전체 "1000"으로 변경 한 다음 동일한 값을 서버로 내보내는 방식으로이 오류를 우회했습니다. :)


0

나는 그것을 해결하기 위해 쿼리 아래에 사용 된 동일한 문제에 직면했습니다.

DB를 생성하는 동안 utf-8 인코딩을 사용할 수 있습니다.

예. create database my_db character set utf8 collate utf8mb4;

편집 : (댓글의 제안 고려) utf8_bin을 utf8mb4로 변경


2
이것은 나를 올바른 방향으로 가리 켰습니다. 나를 위해 나는 내 데이터 정렬을 변경했다 : utf8_general_ci
이안 Newland에게

2
이것은 올바른 방향이 아닙니다. 이러지 마십시오! MySQL utf8은 아니고 utf8결코 결실을 맺지 말아야 할 버그가있는 독점 형식입니다. utf8mb4true utf8이며 적절한 utf8지원을 위해 권장되는 기본값입니다 .
Geoffrey

utf8mb4mysql에서 사용할 올바른 인코딩입니다utf8
alok

그것은 단지 예일뿐입니다-어쨌든 나는 대답을 업데이트했습니다.
Sudhir Dhumal
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.