Programming

# 1071-지정된 키가 너무 깁니다.

procodes 2020. 2. 12. 23:45
반응형

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


다음 명령을 실행할 때 :

ALTER TABLE `mytable` ADD UNIQUE (
`column1` ,
`column2`
);

이 오류 메시지가 나타납니다.

#1071 - Specified key was too long; max key length is 767 bytes

column1 및 column2에 대한 정보 :

column1 varchar(20) utf8_general_ci
column2  varchar(500) utf8_general_ci

varchar(20)21 바이트 varchar(500)만 필요하고 501 바이트 만 필요 하다고 생각 합니다. 따라서 총 바이트 수는 522보다 적으며 767보다 작습니다. 왜 오류 메시지가 표시됩니까?

#1071 - Specified key was too long; max key length is 767 bytes

767 바이트는 MySQL 버전 5.6 (및 이전 버전)에서 InnoDB 테이블에 대해 명시된 접두사 제한 입니다. MyISAM 테이블의 길이는 1,000 바이트입니다. MySQL 버전 5.7 이상에서는이 제한이 3072 바이트로 증가했습니다.

또한 utf8mb4로 인코딩 된 큰 char 또는 varchar 필드에 인덱스를 설정하면 767 바이트 (또는 3072 바이트)의 최대 인덱스 접두사 길이를 4로 나누어 191이되어야합니다. utf8mb4 문자의 최대 길이는 4 바이트입니다. utf8 문자의 경우 최대 바이트 접두사 길이는 254가되는 3 바이트입니다.

한 가지 옵션은 VARCHAR 필드에 하한을 두는 것입니다.

이 문제에 대한 응답 에 따른 또 다른 옵션 은 전체 금액이 아닌 열의 하위 집합을 얻는 것입니다.

ALTER TABLE `mytable` ADD UNIQUE ( column1(15), column2(200) );

키를 적용 할 필요가있을 때 조정하지만,이 엔티티와 관련된 데이터 모델을 검토하여 MySQL 제한에 부딪치지 않고 의도 한 비즈니스 규칙을 구현할 수있는 개선 사항이 있는지 알아볼 가치가 있는지 궁금합니다.


INNODB / Utf-8에 문제가 발생 UNIQUE하여 VARCHAR(256)필드에 색인 을 넣으려고하면로 전환하십시오 VARCHAR(255). 255가 한계 인 것 같습니다.


당신이 한계에 도달했을 때. 다음을 설정하십시오.

  • 이노 DB utf8 VARCHAR(255)
  • 이노 DB utf8mb4 VARCHAR(191)

MySQL은 문자열에서 문자 당 바이트 수에 대해 최악의 경우를 가정합니다. MySQL 'utf8'인코딩의 경우, 문자 당 3 바이트입니다. 해당 인코딩은 U+FFFF. MySQL 'utf8mb4'인코딩의 경우, 문자 당 4 바이트입니다. 이는 MySQL이 실제 UTF-8을 호출하기 때문입니다.

따라서 'utf8'을 사용한다고 가정하면 첫 번째 열에는 60 바이트의 인덱스가 있고 두 번째 열에는 1500 바이트가 필요합니다.


이 쿼리를 쿼리 전에 실행하십시오.

SET @@global.innodb_large_prefix = 1;

이로 제한이 증가합니다 3072 bytes.


어떤 문자 인코딩을 사용하고 있습니까? UTF-16과 같은 일부 문자 집합은 문자 당 하나 이상의 바이트를 사용합니다.


라 라벨 프레임 워크 솔루션

당으로 Laravel 5.4 * 문서. ; 다음과 같이 파일 boot메소드 내에서 기본 문자열 길이를 설정해야 app/Providers/AppServiceProvider.php합니다.

use Illuminate\Support\Facades\Schema;

public function boot() 
{
    Schema::defaultStringLength(191); 
}

Laravel 5.4. * 문서 에서 제공 한이 수정에 대한 설명 :

라 라벨은 utf8mb4기본적으로 문자 세트를 사용하는데 , 여기에는 데이터베이스에 "이모 지"를 저장하는 기능이 포함됩니다. 5.7.7 릴리스 이전의 MySQL 버전 또는 10.2.2 릴리스 이전의 MariaDB를 실행중인 경우, MySQL이 인덱스를 작성하기 위해 마이그레이션에서 생성 된 기본 문자열 길이를 수동으로 구성해야 할 수도 있습니다. 에서 Schema::defaultStringLength메소드 를 호출하여이를 구성 할 수 있습니다 AppServiceProvider.

또는 innodb_large_prefix데이터베이스에 대한 옵션을 활성화 할 수 있습니다. 이 옵션을 올바르게 활성화하는 방법에 대한 지침은 데이터베이스 설명서를 참조하십시오.


varchar (20)에는 21 바이트 만 필요하지만 varchar (500)에는 501 바이트 만 필요하다고 생각합니다. 따라서 총 바이트 수는 522보다 적으며 767보다 작습니다. 왜 오류 메시지가 표시됩니까?

UTF8 문자 당 3 바이트가 필요 귀하의 경우 그래서, 문자열을 저장하기 = 20 * 3 + 500 * 3 = 20 + 500 자 1560 입니다 바이트 이상의 허용 된 767 바이트.

UTF8의 제한은 767/3 = 255 자 이며, 문자 당 4 바이트를 사용하는 UTF8mb4의 경우 767/4 = 191 자입니다.


제한보다 긴 열을 사용해야하는 경우이 문제에 대한 두 가지 솔루션이 있습니다.

  1. "저렴한"인코딩을 사용하십시오 (문자 당 더 적은 바이트가 필요합니다)
    내 경우에는 SEO 문자열을 포함하는 열에 고유 색인을 추가해야했습니다. SEO에는 [A-z0-9\-]문자 만 사용하기 때문에 문자 latin1_general_ci당 하나의 바이트 만 사용했습니다. 따라서 열의 길이는 767 바이트입니다.
  2. 열에서 해시를 만들고 그에 대해서만 고유 인덱스를 사용하십시오
    . 다른 옵션은 SEO의 해시를 저장할 다른 열을 생성하는 것이 었습니다.이 열에는 UNIQUESEO 값이 고유해야합니다. 또한 KEY검색 속도를 높이기 위해 원래 SEO 열에 색인을 추가 합니다.

오류 메시지가 표시되는 이유에 대한 답변은 이미 많은 사용자가 이미 답변했습니다. 내 대답은 그대로 수정하고 사용하는 방법에 관한 것입니다.

이 링크 에서 참조하십시오 .

  1. MySQL 클라이언트 (또는 MariaDB 클라이언트)를 엽니 다. 명령 줄 도구입니다.
  2. 암호를 묻고 올바른 암호를 입력하십시오.
  3. 이 명령을 사용하여 데이터베이스를 선택하십시오 use my_database_name;

데이터베이스가 변경됨

  1. set global innodb_large_prefix=on;

쿼리 OK, 영향을받는 0 개의 행 (0.00 초)

  1. set global innodb_file_format=Barracuda;

쿼리 OK, 영향을받는 0 개의 행 (0.02 초)

  1. 쉬운 관리를 위해 phpMyAdmin 또는 이와 유사한 데이터베이스로 이동하십시오. > 데이터베이스 선택> 테이블 구조 보기 > 작업 탭으로 이동 하십시오. > ROW_FORMATDYNAMIC으로 변경 하고 변경 사항을 저장하십시오.
  2. 테이블 구조 탭으로 이동 > 고유 버튼을 클릭하십시오 .
  3. 끝난. 이제 오류가 없어야합니다.

이 수정의 문제점은 db를 다른 서버 (예 : localhost에서 실제 호스트로)로 내보내고 해당 서버에서 MySQL 명령 행을 사용할 수없는 경우입니다. 거기에서 작동시킬 수 없습니다.


Specified key was too long; max key length is 767 bytes

latin-1문자 세트 를 사용하는 경우에만 1 바이트가 1 문자이므로 메시지가 표시 됩니다. 을 사용하면 utf8키 열을 정의 할 때 각 문자가 3 바이트로 간주됩니다. 을 사용하면 utf8mb4키 열을 정의 할 때 각 문자가 4 바이트 인 것으로 간주됩니다. 따라서 키 필드의 문자 제한에 1, 3 또는 4를 곱하면 키 필드에서 허용하려는 바이트 수를 결정할 수 있습니다. uft8mb4를 사용하는 경우 기본 InnoDB 기본 키 필드에 대해 191 자만 정의 할 수 있습니다. 767 바이트를 위반하지 마십시오.


긴 열의 md5 열을 추가 할 수 있습니다


utf8mb4를 사용하여 VARCHAR (255) 필드에 UNIQUE 인덱스를 추가하려고 할 때이 문제가 발생했습니다. 문제가 이미 여기에 잘 설명되어 있지만, 우리가 이것을 이해하고 해결하는 방법에 대한 실용적인 조언을 추가하고 싶었습니다.

utf8mb4를 사용할 때 문자는 4 바이트로 계산되는 반면 utf8에서는 3 바이트로 계산 될 수 있습니다. InnoDB 데이터베이스에는 인덱스에 767 바이트 만 포함될 수있는 제한이 있습니다. 따라서 utf8을 사용할 때는 255자를 저장할 수 있지만 (767/3 = 255) utf8mb4를 사용하면 191자를 저장할 수 있습니다 (767/4 = 191).

VARCHAR(255)utf8mb4를 사용하여 필드에 대한 일반 색인을 절대적으로 추가 할 수 있지만 다음과 같이 색인 크기가 191 자에서 자동으로 잘립니다 unique_key.

191 자에서 잘린 색인을 보여주는 Sequel Pro 스크린 샷

일반 인덱스는 MySQL이 데이터를 더 빨리 검색하는 데 도움을주기 위해 사용되기 때문에 좋습니다. 전체 필드를 색인 할 필요는 없습니다.

그렇다면 왜 MySQL은 일반 인덱스에 대해 인덱스를 자동으로 자르지 만 고유 인덱스에 대해 시도 할 때 명시적인 오류가 발생합니까? 글쎄, MySQL이 삽입되거나 업데이트되는 값이 이미 존재하는지 알아낼 수 있으려면 실제로 값의 일부가 아닌 전체 값을 인덱싱해야합니다.

하루가 끝날 때 필드에 고유 인덱스를 사용하려면 필드의 전체 내용이 인덱스에 맞아야합니다. utf8mb4의 경우 이는 VARCHAR 필드 길이를 191 자 이하로 줄이는 것을 의미합니다. 해당 테이블 또는 필드에 utf8mb4가 필요하지 않은 경우 utf8로 다시 드롭하고 255 개의 길이 필드를 유지할 수 있습니다.


내 원래 답변은 다음과 같습니다.

데이터베이스를 삭제하고 다음과 같이 다시 작성하면 오류가 사라집니다.

drop database if exists rhodes; create database rhodes default CHARACTER set utf8 default COLLATE utf8_general_ci;

그러나 모든 경우에 작동하지는 않습니다.

실제로 문자 세트 utf8(또는 utf8mb4)가있는 VARCHAR 열에서 특정 길이보다 긴 문자가있는 VARCHAR 열에 인덱스를 사용하면 문제가 발생 합니다. 의 경우 utf8mb4특정 길이는 191입니다.

MySQL 데이터베이스에서 긴 인덱스를 사용하는 방법에 대한 자세한 내용은이 기사의 긴 인덱스 섹션을 참조하십시오. http://hanoian.com/content/index.php/24-automate-the-converting-a-mysql-database- 문자 세트에서 UTF-8로


이 문제를 다음과 같이 수정했습니다.

varchar(200) 

로 교체

varchar(191)

200 이상인 모든 varchar는 191로 바꾸거나 텍스트를 설정합니다.


5 가지 해결 방법 :

한계는 5.7.7 (MariaDB 10.2.2?)에서 증가했습니다. 그리고 5.6 (10.1)에 약간의 작업으로 증가 할 수 있습니다.

CHARACTER SET utf8mb4를 사용하려고 시도하여 한계에 도달 한 경우 그런 다음 오류 중 하나를 피하려면 다음 중 하나를 수행하십시오 (각각 단점이 있음).

⚈  Upgrade to 5.7.7 for 3072 byte limit -- your cloud may not provide this;
⚈  Change 255 to 191 on the VARCHAR -- you lose any values longer than 191 characters (unlikely?);
⚈  ALTER .. CONVERT TO utf8 -- you lose Emoji and some of Chinese;
⚈  Use a "prefix" index -- you lose some of the performance benefits.
⚈  Or... Stay with older version but perform 4 steps to raise the limit to 3072 bytes:

SET GLOBAL innodb_file_format=Barracuda;
SET GLOBAL innodb_file_per_table=1;
SET GLOBAL innodb_large_prefix=1;
logout & login (to get the global values);
ALTER TABLE tbl ROW_FORMAT=DYNAMIC;  -- (or COMPRESSED)

-http : //mysql.rjweb.org/doc.php/limits#767_limit_in_innodb_indexes


나는이 주제에 대한 검색을 마침내 마침내 약간의 사용자 정의 변경을 얻었다

MySQL 워크 벤치 6.3.7 버전의 경우 그래픽 간 단계 사용 가능

  1. Workbench를 시작하고 연결을 선택하십시오.
  2. 관리 또는 인스턴스로 이동하여 옵션 파일을 선택하십시오.
  3. Workbench가 구성 파일을 읽을 수있는 권한을 요청한 후 확인을 두 번 눌러 허용하십시오.
  4. 중앙 위치에 관리자 옵션 파일 창이 나타납니다.
  5. InnoDB 탭으로 이동하여 innodb_large_prefix가 General 섹션에서 확인되지 않은 경우 확인하십시오.
  6. innodb_default_row_format 옵션 값을 DYNAMIC으로 설정하십시오.

6.3.7 이하 버전의 경우 직접 옵션을 사용할 수 없으므로 명령 프롬프트로 이동해야합니다.

  1. CMD를 관리자로 시작하십시오.
  2. mysql 서버가 설치되어있는 director로 이동 대부분의 경우 "C : \ Program Files \ MySQL \ MySQL Server 5.7 \ bin"에 있으므로 명령은 "cd \" "cd Program Files \ MySQL \ MySQL Server 5.7 \ bin"입니다.
  3. 이제 mysql -u userName -p databasescheema 명령을 실행하십시오. 이제 각 사용자의 비밀번호를 요청했습니다. 비밀번호를 입력하고 mysql 프롬프트에 입력하십시오.
  4. 일부 전역 설정을 설정해야합니다. set global innodb_large_prefix = on; 전역 설정 innodb_file_format = barracuda; 전역으로 설정 innodb_file_per_table = true;
  5. 이제 마지막으로 필요한 테이블의 ROW_FORMAT을 기본적으로 COMPACT로 변경해야합니다.이를 DYNAMIC으로 설정해야합니다.
  6. 다음 명령을 사용하십시오 alter table table_name ROW_FORMAT = DYNAMIC;
  7. 끝난

데이터 정렬을 변경하십시오. 거의 모든 것을 지원 하는 utf8_general_ci사용할 수 있습니다


라 라벨 5.7 또는 5.6 또는 5.8

따라야 할 단계

  1. 로 이동하십시오 App\Providers\AppServiceProvider.php.
  2. 이것을 공급자 use Illuminate\Support\Facades\Schema;에게 맨 위에 추가하십시오 .
  3. 부팅 기능 내부 추가 Schema::defaultStringLength(191);

그 모든 것을 즐기십시오.


테이블을 만들 때로 변경 utf8mb4하면 utf8문제가 해결되었습니다. 예를 들면 다음 CREATE TABLE ... DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;과 같습니다 CREATE TABLE ... DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;.


교체 utf8mb4utf8가져 오기 파일입니다.

여기에 이미지 설명을 입력하십시오


아래에 주어진 열을 기준으로 두 개의 가변 문자열 열이 utf8_general_ci데이터 정렬을 사용하고 있습니다 ( utf8문자 세트가 암시 됨).

MySQL에서 utf8문자셋은 각 문자에 최대 3 바이트사용합니다 . 따라서 500 * 3 = 1500 바이트를 할당해야하며 이는 MySQL이 허용하는 767 바이트보다 훨씬 큽니다. 그래서이 1071 오류가 발생합니다.

즉, 모든 문자 세트가 단일 바이트 표현이 아니기 때문에 문자 세트의 바이트 표현을 기반으로 문자 수를 계산해야합니다 (예상 한대로). utf8MySQL의 IE 는 문자 당 최대 3 바이트, 767/3 × 255를 사용합니다 문자, 및 utf8mb4최대 4 바이트 표현, 767/4 x 191 문자.

또한 MySQL로 알려져 있습니다

column1 varchar(20) utf8_general_ci
column2  varchar(500) utf8_general_ci

이 쿼리는 인덱스가 최대 길이를 위반하는 열을 감지하는 데 유용하다는 것을 알았습니다.

SELECT
  c.TABLE_NAME As TableName,
  c.COLUMN_NAME AS ColumnName,
  c.DATA_TYPE AS DataType,
  c.CHARACTER_MAXIMUM_LENGTH AS ColumnLength,
  s.INDEX_NAME AS IndexName
FROM information_schema.COLUMNS AS c
INNER JOIN information_schema.statistics AS s
  ON s.table_name = c.TABLE_NAME
 AND s.COLUMN_NAME = c.COLUMN_NAME 
WHERE c.TABLE_SCHEMA = DATABASE()
  AND c.CHARACTER_MAXIMUM_LENGTH > 191 
  AND c.DATA_TYPE IN ('char', 'varchar', 'text')

있는지 확인하시기 바랍니다 sql_mode같다

sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

그렇다면

sql_mode=NO_ENGINE_SUBSTITUTION

또는

my.cnf 파일을 변경하여 서버를 다시 시작하십시오 (다음과 같이 입력).

innodb_large_prefix=on


불만족스러운 색인 필드의 CHARSET을 "latin1"로 변경하십시오. 즉 ALTER TABLE tbl CHANGE myfield myfield varchar (600) CHARACTER SET latin1 DEFAULT NULL;
latin1은 4 개 대신 1 개의 문자에 1 바이트를 사용합니다.


다음과 같은 것을 만드는 경우 :

CREATE TABLE IF NOT EXISTS your_table (
  id int(7) UNSIGNED NOT NULL AUTO_INCREMENT,
  name varchar(256) COLLATE utf8mb4_bin NOT NULL,
  PRIMARY KEY (id),
  UNIQUE KEY name (name)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1 ROW_FORMAT=FIXED;

그것은 다음과 같아야합니다

CREATE TABLE IF NOT EXISTS your_table (
      id int(7) UNSIGNED NOT NULL AUTO_INCREMENT,
      name varchar(256) COLLATE utf8mb4_bin NOT NULL,
      PRIMARY KEY (id)
    ) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1 ROW_FORMAT=FIXED;

그러나 코드에서 해당 열의 고유성을 확인하거나 새 열을 varchar 열의 MD5 또는 SHA1로 추가해야합니다.


필자의 경우 Linux 리디렉션 출력 / 입력 문자를 사용하여 데이터베이스를 백업 할 때이 문제가 발생했습니다. 따라서 아래 설명과 같이 구문을 변경합니다. 추신 : 리눅스 또는 맥 터미널을 사용합니다.

백업 (> 리디렉션없이)

# mysqldump -u root -p databasename -r bkp.sql

복원 (<redirect없이)

# mysql -u root -p --default-character-set=utf8 databasename
mysql> SET names 'utf8'
mysql> SOURCE bkp.sql

"지정된 키가 너무 깁니다. 최대 키 길이는 767 바이트입니다"라는 오류가 사라졌습니다.


접두사 제한으로 인해이 오류가 발생합니다. 767 바이트는 5.7 이전의 MySQL 버전에서 InnoDB 테이블에 대해 명시된 접두사 제한입니다. MyISAM 테이블의 길이는 1,000 바이트입니다. MySQL 버전 5.7 이상에서는이 제한이 3072 바이트로 증가했습니다.

오류가 발생한 서비스에서 다음을 실행하면 문제가 해결됩니다. MYSQL CLI에서 실행해야합니다.

SET GLOBAL innodb_file_format=Barracuda;
SET GLOBAL innodb_file_per_table=on;
SET GLOBAL innodb_large_prefix=on;

인덱스 길이 및 MySQL / MariaDB


라 라벨은 기본적으로 utf8mb4 문자 세트를 사용하는데 , 여기에는 데이터베이스에 "이모 지" 를 저장하는 기능이 포함 됩니다. 5.7.7 릴리스 이전의 MySQL 버전 또는 10.2.2 릴리스 이전의 MariaDB를 실행중인 경우, MySQL이 인덱스를 작성하기 위해 마이그레이션에서 생성 된 기본 문자열 길이를 수동으로 구성해야 할 수도 있습니다. AppServiceProvider에서 Schema :: defaultStringLength 메소드 를 호출하여이를 구성 할 수 있습니다 .

use Illuminate\Support\Facades\Schema;

/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    Schema::defaultStringLength(191);
}

또는 데이터베이스에 대해 innodb_large_prefix 옵션을 활성화 할 수 있습니다. 이 옵션을 올바르게 활성화하는 방법에 대한 지침은 데이터베이스 설명서를 참조하십시오.

공식 라 라벨 문서에서 참조 : https://laravel.com/docs/5.7/migrations


그것을 고치기 위해 이것은 매력처럼 작동합니다.

ALTER DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;

필자의 경우 열 크기를 200으로 제한하여 기본 키 / 고유 키 조합을 변경 한 후 "# 1071-지정된 키가 너무 길었습니다. 최대 키 길이는 767 바이트입니다"라는 문제가 해결되었습니다.

ALTER TABLE `mytable` ADD UNIQUE (
`column1` (200) ,
`column2` (200)
);

참고 URL : https://stackoverflow.com/questions/1814532/1071-specified-key-was-too-long-max-key-length-is-767-bytes



반응형