sourcecode

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

copyscript 2023. 10. 31. 22:32
반응형

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

다음 명령을 실행하면 다음과 같습니다.

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바이트만 필요합니다.따라서 총 바이트 수는 767보다 적은 522개입니다.그런데 왜 오류 메시지가 나왔을까요?

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

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

당신은 또한 당신이 큰 차르에 지수를 설정하는 것을 알아야 합니다.varchar필드는utf8mb4인코딩된 경우, 최대 인덱스 접두사 길이인 767 바이트(또는 3072 바이트)를 4로 나누어 191을 생성해야 합니다.이것은 a의 최대 길이가utf8mb4문자는 4바이트입니다.일단은utf8문자는 최대 인덱스 접두사 길이가 255(또는 - null-terminator 제외, 254자)가 되는 3바이트가 됩니다.

한 가지 선택 사항은 제한을 더 낮게 두는 것입니다.VARCHAR들녘

(이 문제에 대한 응답에 따라) 또 다른 옵션은 전체 양이 아닌 열의 부분 집합을 얻는 것입니다. 즉:

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

키를 가져와야 지원할 수 있기 때문에 조정하지만, MySQL 제한에 영향을 주지 않고 의도한 비즈니스 규칙을 구현할 수 있는 개선 사항이 있는지 이 엔티티와 관련된 데이터 모델을 검토해 볼 가치가 있는지 궁금합니다.

한계에 다다르면.다음을 설정합니다.

  • 이노드비utf8 VARCHAR(255)
  • 이노드비utf8mb4 VARCHAR(191)

InnoDB에 문제가 있는 사람이 있다면 그리고utf8A를 넣으려고 하는 charsetUNIQUE색인을 보다VARCHAR(256)필드, 로 전환합니다.VARCHAR(255) 255가 한계인 것 같습니다.

MySQL은 문자열의 문자당 바이트 수에 대해 최악의 경우를 가정합니다.MySQL 'utf8' 인코딩의 경우, 해당 인코딩은 다음을 초과하는 문자를 허용하지 않으므로 문자당 3바이트입니다.U+FFFF는 MySQL이 실제 MySQL 'utf8mb4' 인코딩의 경우 문자당 4바이트인데, 이는 MySQL이 실제 UTF-8이라고 부르는 것이기 때문입니다.

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

쿼리 전에 다음 쿼리를 실행합니다.

SET @@global.innodb_large_prefix = 1;

이것은 제한을 증가시킬 것입니다.3072 bytes.

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

Laravel 5.4.* 설명서에 따르면, 기본 문자열 길이를 설정해야 합니다.bootapp/Providers/AppServiceProvider.php파일은 다음과 같습니다.

use Illuminate\Support\Facades\Schema;

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

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

라라벨은 다음을 사용합니다.utf8mb4기본적으로 설정된 문자로, 데이터베이스에 emojis를 저장하기 위한 지원이 포함합니다. 버전의 하는 경우 이 마이그레이션에 인덱스를 해야 할 수 5.7.7의 MySQL하거나 10.22 릴리스보다 이전 버전의 MariaDB를 실행하는 경우 MySQL이 마이그레이션에 대한 인덱스를 생성하려면 마이그레이션에 의해 생성된 기본 문자열 길이를 수동으로 구성해야 할 수 있습니다.를 호출하여 이를 구성할 수 있습니다.Schema::defaultStringLength당신 안의 메소드AppServiceProvider.

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

어떤 문자 인코딩을 사용하고 계십니까?UTF-16 등과 같은 일부 문자 집합은 문자당 1바이트 이상을 사용합니다.

교체하다utf8mb4와 함께utf8당신의 수입 파일에.

enter image description here

하지만 주목하세요.utf8charset은 더 이상 사용되지 않으며 이모지와 같은 모든 유니코드 문자를 지원하지 않으므로 이렇게 하면 전체 유니코드 지원을 잃게 됩니다.

varchar(20)는 21바이트만 필요하고 varchar(500)는 501바이트만 필요하다고 생각합니다.따라서 총 바이트 수는 767보다 적은 522개입니다.그런데 왜 오류 메시지가 나왔을까요?

UTF8의 경우 문자열을 저장하려면 문자당 3바이트가 필요하므로 20+500자 = 20*3+500*3 = 1560바이트로 허용된 767바이트보다 많습니다.

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


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

  1. "더 저렴한" 인코딩을 사용합니다(문자당 바이트 수가 적은 인코딩).
    저의 경우, 기사의 SEO 문자열이 포함된 열에 유니크 인덱스를 추가해야 했습니다. 왜냐하면 저는 오직 제가 사용하기 때문입니다.[A-z0-9\-]SEO의 캐릭터, 제가 사용했습니다.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;

쿼리 확인, 영향을 받는 행 0개(0.00초)

  1. set global innodb_file_format=Barracuda;

쿼리 확인, 영향을 받는 행 0개(0.02초)

  1. 쉬운 관리를 위해 phpMyAdmin 등에서 데이터베이스로 이동합니다.> database > View table structure > Go to Operations 탭을 선택합니다.> ROW_FORMATDynamic으로 변경하고 변경사항을 저장합니다.
  2. 테이블 구조 탭으로 이동 > 유니크 버튼 클릭
  3. 됐습니다. 이제 오류가 없어야 합니다.

이 수정의 문제는 다른 서버(예: localhost에서 realhost로)에 db를 내보내고 해당 서버에서 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에 대해 191자만 정의할 수 있습니다.767바이트를 위반하지 마십시오.

5가지 해결 방법:

5.7.7(MariaDB 10.2.2?)에서 제한이 상향 조정되었습니다.그리고 5.6(10.1)에서 약간의 작업을 통해 증가할 수 있습니다.

CHARKER 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

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

Laravel 5.7 ~ 9.0의 경우

따라야 할 단계

  1. 에 가다App\Providers\AppServiceProvider.php.
  2. 공급자에 추가use Illuminate\Support\Facades\Schema;맨 위에
  3. 부팅 기능 내부에 추가Schema::defaultStringLength(191);

그것만, 즐겨요.

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개 길이의 필드를 유지할 수 있습니다.

다음과 같은 문제를 해결했습니다.

varchar(200) 

로 대체된

varchar(191)

200개 이상의 고유 또는 기본 varchar 키는 모두 191개로 대체하거나 텍스트로 설정합니다.

제 원래 대답은 이렇습니다.

데이터베이스를 삭제하고 이렇게 다시 만들면 오류가 사라집니다.

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

하지만 모든 경우에 효과가 있는 것은 아닙니다.

실제로 VARCHAR 열에서 문자 집합으로 인덱스를 사용하는 문제입니다.utf8(또는utf8mb4특정 길이 이상의 문자를 가진 VARCHAR 열이 있습니다.의 .utf8mb4, 그 특정 길이는 191입니다.

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

그것을 고치기 위해서, 이것은 나에게 매력적으로 작용합니다.

ALTER DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;

나는 이 주제에 대해 검색을 좀 했고 마침내 사용자 정의 변경을 받았습니다.

MySQL 워크벤치용 6.3.7 버전 그래픽 인터페이즈 사용 가능

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

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

  1. CMD를 관리자로 시작합니다.
  2. mysql 서버가 설치되어 있는 디렉터로 이동대부분의 경우 "C:\Program Files\MySQL\MySQL Server 5.7\bin" 따라서 명령어는 "cd" "cd Program Files\My"입니다.SQL\MySQL Server 5.7\bin".
  3. Now Run command mysql -u userName -p databascheme Now 각 사용자의 비밀번호를 요청했습니다.암호를 입력하고 mysql 프롬프트에 입력합니다.
  4. 일부 글로벌 설정을 해야 하기 때문에 아래 명령어를 하나씩 글로벌 innodb_large_prefix=on으로 설정하고, 글로벌 innodb_file_format=barracuda으로 설정하고, 글로벌 innodb_file_per_table=true로 설정하고,
  5. 이제 마지막으로 필요한 테이블의 ROW_FORMAT을 기본적으로 COMPRATE로 변경해야 합니다.
  6. 다음 명령 변경 테이블_name ROW_FORMAT=Dynamic을 사용합니다.
  7. 다 했어요.

인덱스 길이 & MySQL / MariaDB


Laravel은 기본적으로 utf8mb4 문자 집합을 사용하며, 여기에는 "emoji"를 데이터베이스에 저장할 수 있는 지원이 포함됩니다.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://www.scratchcode.io/specified-key-too-long-error-in-laravel/

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

콜렉션을 바꿉니다.거의 모든 기능을 지원하는 utf8_general_ci를 사용할 수 있습니다.

그냥바꾸기utf8mb4.utf8테이블을 만들때 나의 문제를 해결했습니다.예를 들어,CREATE TABLE ... DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;.CREATE TABLE ... DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;.

이것으로 나의 문제가 해결되었습니다.

ALTER DATABASTER dbname Character Set utf8 COLATE utf8_general_ci;

아래에 주어진 열을 기준으로, 그 2개의 가변 문자열 열은utf8_general_ci대조()utf8문자 집합이 암시됨).

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

즉, 모든 문자 집합이 (추정한 대로) 단일 바이트 표현이 아니기 때문에 문자 집합의 바이트 표현을 기반으로 문자 수를 계산해야 합니다.utf8MySQL은 최대 문자당 3바이트, 767/3 ≈255 문자를 사용합니다.utf8mb4, 최대 4바이트, 767/4≈191 문자로 표현할 수 있습니다.

또한 MySQL은

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

저의 경우 리눅스 리디렉션 출력/입력 문자를 사용하여 데이터베이스를 백업할 때 이 문제가 발생했습니다.따라서 아래와 같이 구문을 변경합니다.추신: 리눅스나 맥 단말기를 사용합니다.

백업( > 리디렉션 없음)

# 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바이트입니다"라는 오류가 사라졌습니다.

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

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 파일을 변경합니다(다음 putting).

innodb_large_prefix=on

접두사 제한으로 인해 이 오류가 발생합니다.MySQL 5.7 이전 버전의 InnoDB 테이블에 대해 명시된 접두사 제한은 767바이트이며 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에는 최대 키 길이 제한이 있습니다.

  • InnoDB — 최대 키 길이는 1,536바이트(8kb 페이지 크기의 경우) 및 768(4kb 페이지 크기의 경우)입니다(출처: Dev.MySQL.com .
  • My ISAM — 최대 키 길이는 1,000바이트입니다(Source Dev).MySQL.com ).

바이트 단위로 계산됩니다.따라서 UTF-8 문자가 키에 저장되는 데 1바이트 이상이 걸릴 수 있습니다.

따라서 두 가지 솔루션만 즉시 사용할 수 있습니다.

  • 텍스트 유형의 첫 번째 n번째 문자만 색인화합니다.
  • 만들기FULL TEXTsearch — ElasticSearch와 유사한 방식으로 텍스트 내의 모든 것을 검색할 수 있습니다.

텍스트 유형의 첫 번째 N번째 문자 색인화

표를 작성할 경우, 다음 구문을 사용하여 일부 필드의 처음 255자를 색인화합니다.KEY 어떤 텍스트 키 (일부 텍스트(255)) 거죠 이와 같습니다.

CREATE TABLE `MyTable` (
    `id` int(11) NOT NULL auto_increment,
    `SomeText` TEXT NOT NULL,
    PRIMARY KEY  (`id`),
    KEY `sometextkey` (`SomeText`(255))
);

테이블이 이미 있는 경우, 다음을 사용하여 필드에 고유 키를 추가할 수 있습니다.ADD UNIQUE((20)); 거죠 이와 같습니다.

ALTER TABLE
MyTable
ADD UNIQUE(`ConfigValue`(20));

필드 이름이 예약된 MySQL 키워드가 아닌 경우 필드 이름 주변에 백틱('``)이 필요하지 않습니다.

전체 텍스트 검색 만들기

Full Text(전체 텍스트) 검색을 사용하면 해당 파일의 전체 값을 검색할 수 있습니다.TEXT field를 시킬 수 있습니다. 를 사용하면 단어 전체를 일치시킬 수 있습니다.NATURAL LANGUAGE MODE, 다른 모드 중 하나를 사용하는 경우 부분 단어 일치를 선택할 수 있습니다.FullText 옵션에 대한 자세한 내용은 여기에서 확인하십시오. Dev.MySQL.com

텍스트를 사용하여 표를 작성한 후 전체 텍스트 색인을 추가합니다.

ALTER TABLE
        MyTable
ADD FULLTEXT INDEX
        `SomeTextKey` (`SomeTextField` DESC);

그런 다음 테이블을 뒤집니다.

SELECT
        MyTable.id, MyTable.Title,
MATCH
        (MyTable.Text)
AGAINST
        ('foobar' IN NATURAL LANGUAGE MODE) AS score
FROM
        MyTable
HAVING
        score > 0
ORDER BY
        score DESC;

나는 varchar에서 nvarchar로 변화가 있어, 나에게 적합합니다.

언급URL : https://stackoverflow.com/questions/38659010/specified-key-too-long-using-utf8mb4-general-ci-with-myisam

반응형