문제

다음 명령을 실행했을 때 :

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

이 오류 메시지를 받았습니다.

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

컬럼 1 및 컬럼 2에 대한 정보 :

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 바이트가됩니다.

당신이 가진 옵션 중 하나는 바르 차르 필드에 하한을 배치하는 것입니다.

또 다른 옵션 (.에 따르면 이 문제에 대한 응답)는 전체 금액이 아닌 열의 하위 집합을 가져 오는 것입니다.

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

적용 할 키를 얻으려면 조정하지만,이 엔티티와 관련하여 데이터 모델을 검토하여 MySQL 제한에 도달하지 않고도 의도 된 비즈니스 규칙을 구현할 수있는 개선 사항이 있는지 확인하는 것이 가치가 있는지 궁금합니다.

다른 팁

누군가가 innodb / utf-8에 문제가있는 경우 UNIQUE a에 인덱스 VARCHAR(256) 필드, 전환하십시오 VARCHAR(255). 255가 한계 인 것 같습니다.

한계에 도달하면. 다음을 설정하십시오.

  • innodb utf8 VARCHAR(255)
  • innodb utf8mb4 VARCHAR(191)

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

따라서 'UTF8'을 사용한다고 가정하면 첫 번째 열은 60 바이트의 색인을, 두 번째 열은 1500을 사용합니다.

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

SET @@global.innodb_large_prefix = 1;

이것은 한계가 증가합니다 3072 bytes.

어떤 캐릭터 인코딩을 사용하고 있습니까? 일부 문자 세트 (UTF-16 등)는 문자 당 둘 이상의 바이트를 사용합니다.

Laravel 프레임 워크를위한 솔루션

에 따라 Laravel 5.4.* 문서; 기본 문자열 길이를 내부에 설정해야합니다. boot 방법의 방법 app/Providers/AppServiceProvider.php 다음과 같이 파일 :

use Illuminate\Support\Facades\Schema;

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

이 수정 사항에 대한 설명 Laravel 5.4.* 문서:

Laravel을 사용합니다 utf8mb4 기본적으로 설정된 문자는 데이터베이스에 "이모티콘"저장 지원을 포함합니다. 10.2.2 릴리스보다 오래된 5.7.7 릴리스 또는 mariadB보다 오래된 MySQL 버전을 실행하는 경우 MySQL이 인덱스를 생성하려면 마이그레이션으로 생성 된 기본 문자열 길이를 수동으로 구성해야 할 수도 있습니다. 호출하여이를 구성 할 수 있습니다 Schema::defaultStringLength 당신의 방법 AppServiceProvider.

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

Varchar (20)는 21 바이트 만 필요하지만 Varchar (500)는 501 바이트 만 필요하다고 생각합니다. 따라서 총 바이트는 522, 767 미만입니다. 왜 오류 메시지를 얻었습니까?

UTF8은 문자 당 3 바이트가 필요합니다 문자열을 저장하려면 20 + 500 문자 = 20*3 + 500*3 = 1560 바이트입니다 이상 허용된 767 바이트.

UTF8의 한계는 767/3 =입니다 255 자, 문자 당 4 바이트를 사용하는 UTF8MB4의 경우 767/4 =입니다. 191 캐릭터.


한계보다 더 긴 열을 사용해야하는 경우이 문제에 대한 두 가지 해결책이 있습니다.

  1. "저렴한"인코딩을 사용하십시오 (문자 당 바이트가 적은 것)
    제 경우에는 SEO 문자열이 포함 된 열에 고유 한 인덱스를 추가해야했습니다. [A-z0-9\-] SEO의 문자, 나는 사용했습니다 latin1_general_ci 문자 당 하나의 바이트 만 사용하므로 열은 767 바이트 길이를 가질 수 있습니다.
  2. 열에서 해시를 만들고 고유 한 색인 만 사용하십시오.
    저를위한 다른 옵션은 SEO의 해시를 저장하는 다른 열을 만드는 것이 었습니다. UNIQUE SEO 값이 고유한지 확인하는 핵심. 나는 또한 추가 할 것이다 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_format 에게 동적 변경 사항을 저장합니다.
  2. 테이블로 가십시오 구조 탭> 클릭하십시오 독특한 단추.
  3. 완료. 이제 오류가 없어야합니다.

이 수정의 문제는 DB를 다른 서버 (예 : LocalHost에서 Real Host로)로 내보내고 해당 서버에서 MySQL 명령 줄을 사용할 수없는 경우입니다. 당신은 거기에서 작동하게 할 수 없습니다.

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

1 바이트가 사용하는 경우에만 1 문자와 같기 때문에 그 메시지를 받았습니다. latin-1 캐릭터 세트. 사용하는 경우 utf8, 각 문자는 키 열을 정의 할 때 3 바이트로 간주됩니다. 사용하는 경우 utf8mb4, 각 문자는 키 열을 정의 할 때 4 바이트로 간주됩니다. 따라서 키 필드의 문자 제한에 1, 3 또는 4 (내 예에서)를 곱하여 키 필드가 허용하려는 바이트 수를 결정해야합니다. UFT8MB4를 사용하는 경우 네이티브 인 InnoDB, 1 차 키 필드에 대해서만 191 자만 정의 할 수 있습니다. 767 바이트를 위반하지 마십시오.

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

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

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

정기적 인 색인을 추가 할 수 있습니다 VARCHAR(255) UTF8MB4를 사용하는 필드이지만 인덱스 크기는 191 문자로 자극적으로 잘린 것입니다. unique_key 여기:

Sequel Pro screenshot showing index truncated at 191 characters

일반 인덱스는 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;

그러나 모든 경우에 효과가있는 것은 아닙니다.

실제로 캐릭터 세트와 함께 varchar 열에서 인덱스를 사용하는 문제입니다. utf8 (또는 utf8mb4), 특정 길이의 문자 이상의 Varchar 열이 있습니다. 의 경우 utf8mb4, 특정 길이는 191입니다.

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

이 주제에 대한 검색을 했어요 마침내 사용자 정의 변경이있었습니다.

MySQL Workbench의 경우 6.3.7 버전 그래픽 인터 위상을 사용할 수 있습니다.

  1. 워크 벤치를 시작하고 연결을 선택하십시오.
  2. 관리 또는 인스턴스로 이동하여 옵션 파일을 선택하십시오.
  3. Workbench가 구성 파일을 읽을 수있는 권한을 요청한 다음 OK를 두 번 눌러 허용하는 경우.
  4. 센터 장소 관리자 옵션 파일 창이 온다.
  5. InnoDB 탭으로 이동하여 일반 섹션에서 확인되지 않은 경우 InnoDB_LARGE_PREFIX를 확인하십시오.
  6. innodb_default_row_format 옵션 값을 동적으로 설정하십시오.

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

  1. 관리자로 CMD를 시작하십시오.
  2. MySQL Server가 대부분의 사례를 설치하는 감독으로 이동하십시오.
  3. 이제 명령 mysql -u username -p databasescheema 명령을 실행하십시오. 이제 각 사용자의 비밀번호를 요청하십시오. 비밀번호를 제공하고 MySQL 프롬프트를 입력하십시오.
  4. 일부 전역 설정을 설정해야합니다. 한 번에 한 번에 아래 명령을 입력해야합니다. Global innodb_file_format = barracuda를 설정합니다. 글로벌 innodb_file_per_table = true를 설정하십시오.
  5. 이제 마지막으로 필수 테이블의 row_format을 기본적으로 소형으로 변경해야합니다.
  6. 다음 명령 Alter Table_Name Row_format = Dynamic 사용;
  7. 완료

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

varchar(200) 

대체

varchar(191)

200 개가 넘는 Varchar는 191로 교체하거나 텍스트를 설정합니다.

5 개의 해결 방법 :

한도는 5.7.7 (MariaDB 10.2.2?)에서 제기되었습니다. 5.6 (10.1)의 일부 작업으로 증가 할 수 있습니다.

문자 세트 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

Collation을 변경하십시오. 당신이 사용할 수있는 UTF8_GENERAL_CI 그것은 거의 모든 것을 지원합니다

그냥 변화 utf8mb4 에게 utf8 테이블을 만들 때 문제가 해결되었습니다. 예를 들어: CREATE TABLE ... DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; 에게 CREATE TABLE ... DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;.

Laravel 5.7 또는 5.6 또는 5.8의 경우

따라야 할 단계

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

그 모든 것, 즐기십시오.

아래에서 주어진 열을 기준으로 2 개의 변수 문자열 열이 사용 중입니다. utf8_general_ci 콜라테이션 (utf8 숯이 암시됩니다).

MySQL에서 utf8 Charset은 최대 값을 사용합니다 3 바이트 각 캐릭터에 대해. 따라서 500*3 = 1500 바이트를 할당해야하며, 이는 MySQL이 허용하는 767 바이트보다 훨씬 큽니다. 그렇기 때문에이 1071 오류가 발생합니다.

다시 말해, 모든 숯이 단일 바이트 표현 (가정대로) 이는 것은 아니기 때문에 숯불의 바이트 표현을 기반으로 문자 수를 계산해야합니다. 즉 utf8 MySQL에는 문자 당 최대 3 바이트, 767/3≈255 문자 및 utf8mb4, 최대 4 바이트 표현, 767/4≈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

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

백업 (> 리디렉션없이)

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

복원 (<리디렉션없이)

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

"지정된 키가 너무 길었고 최대 키 길이는 767 바이트"입니다. 단순한 사라졌습니다.

인덱스 길이 및 mysql / mariadb


Laravel을 사용합니다 UTF8MB4 문자 저장 지원을 포함하여 기본적으로 설정합니다 "이모 지" 데이터베이스에서. 10.2.2 릴리스보다 오래된 5.7.7 릴리스 또는 mariadB보다 오래된 MySQL 버전을 실행하는 경우 MySQL이 인덱스를 생성하려면 마이그레이션으로 생성 된 기본 문자열 길이를 수동으로 구성해야 할 수도 있습니다. 호출하여이를 구성 할 수 있습니다 스키마 :: defaultstringlength 당신의 방법 AppServiceProvider :

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

불만 인덱스 필드의 숯이 "Latin1"으로 변경
IE ALTER TABLE TBL Change Myfield Myfield Varchar (600) 문자 세트 LATIN1 기본 NULL;
latin1

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

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로 새 열을 추가해야합니다.

접두사 제한으로 인해이 오류가 발생합니다. 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;

그것을 고치려면, 이것은 나에게 매력처럼 작동합니다.

ALTER DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;

당신이 바뀌었다면 innodb_log_file_size 최근에 효과가있는 이전 가치를 복원하려고 노력하십시오.

저에게는 "#1071- 지정된 키가 너무 길었습니다. 최대 키 길이는 767 바이트"입니다. 열 크기를 200만큼 제한하여 1 차 키 / 고유 키 조합을 변경 한 후 해결되었습니다.

ALTER TABLE `mytable` ADD UNIQUE (
`column1` (200) ,
`column2` (200)
);
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top