# 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.