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

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

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

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을 사용하고 있습니다.



답변

@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옵션 을 사용하지 않는 한 효과가 없습니다 .


답변

이 오류는 인덱스 길이가 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 바이트입니다.


답변

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

원인

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

해결

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

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

    set GLOBAL storage_engine='InnoDb';

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

    SET GLOBAL default_storage_engine = 'InnoDB';

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

참고


답변

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

SET @@global.innodb_large_prefix = 1;

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


답변

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

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


답변

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


답변

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

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

예. create database my_db character set utf8 collate utf8mb4;

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