# 1071 - Kunci yang ditentukan terlalu panjang; panjang kunci maks adalah 767 byte

563

Ketika saya menjalankan perintah berikut:

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

Saya mendapat pesan kesalahan ini:

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

Informasi tentang kolom1 dan kolom2:

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

Saya pikir varchar(20)hanya membutuhkan 21 byte sementara varchar(500)hanya membutuhkan 501 byte. Jadi total byte adalah 522, kurang dari 767. Jadi mengapa saya mendapatkan pesan kesalahan?

#1071 - Specified key was too long; max key length is 767 bytes
Steven
sumber
5
Karena ini bukan 520 byte, melainkan 2080 byte, yang jauh melebihi 767 byte, Anda bisa melakukan column1 varchar (20) dan column2 varchar (170). jika Anda menginginkan karakter / byte equiv, gunakan latin1
Rahly
3
Saya pikir perhitungan Anda agak salah di sini. mysql menggunakan 1 atau 2 byte tambahan untuk mencatat panjang nilai: 1 byte jika panjang maksimum kolom adalah 255 byte atau kurang, 2 jika lebih panjang dari 255 byte. pengkodean utf8_general_ci membutuhkan 3 byte per karakter sehingga varchar (20) menggunakan 61 byte, varchar (500) menggunakan total 1502 bytes 1563 bytes
lackovic10
3
mysql> pilih maxlen, character_set_name dari information_schema.character_sets di mana character_set_name in ('latin1', 'utf8', 'utf8mb4'); maksimal | character_set_name ------ | ------------------- 1 | latin1 ------ | ------------------- 3 | utf8 ------ | ------------------- 4 | utf8mb4
lackovic10
15
'jika Anda ingin karakter / byte equiv, gunakan latin1' Tolong jangan lakukan ini . Latin1 benar-benar menyebalkan. Anda akan menyesali ini.
Stijn de Witt
Lihat stackoverflow.com/a/52778785/2137210 untuk solusinya
Pratik

Jawaban:

490

767 byte adalah batasan awalan yang dinyatakan untuk tabel InnoDB di MySQL versi 5.6 (dan versi sebelumnya). Panjangnya 1.000 byte untuk tabel MyISAM. Dalam versi MySQL 5.7 dan ke atas batas ini telah ditingkatkan menjadi 3072 byte.

Anda juga harus menyadari bahwa jika Anda menetapkan indeks pada bidang char atau varchar besar yang dikodekan utf8mb4, Anda harus membagi panjang awalan indeks maks 767 byte (atau 3072 byte) dengan 4 menghasilkan 191. Ini karena panjang maksimal karakter utf8mb4 adalah empat byte. Untuk karakter utf8 akan menjadi tiga byte yang menghasilkan panjang awalan indeks maksimal 254.

Salah satu opsi yang Anda miliki adalah menempatkan batas bawah pada bidang VARCHAR Anda.

Pilihan lain (sesuai dengan respons terhadap masalah ini ) adalah untuk mendapatkan bagian dari kolom daripada seluruh jumlah, yaitu:

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

Tweak karena Anda perlu mendapatkan kunci untuk diterapkan, tapi saya ingin tahu apakah akan layak untuk meninjau model data Anda mengenai entitas ini untuk melihat apakah ada perbaikan yang akan memungkinkan Anda untuk menerapkan aturan bisnis yang dimaksud tanpa mencapai batasan MySQL.

OMG Ponies
sumber
4
Untuk menerapkan dengan menentukan subset kolom daripada seluruh jumlah. Solusi yang bagus.
Steven
204
Ini tidak menjelaskan mengapa bidang yang jauh di bawah batas panjang melebihi batas panjang ...
Cerin
6
Saya sudah mencoba mengedit informasi @Cerin yang hilang di atas, yang jelas-jelas dianggap hilang oleh orang lain juga, tetapi ditolak karena lebih cocok sebagai komentar. Bagi mereka yang mencoba memahami mengapa 500 + 20> 767 lihat komentar Stefan Endrullis pada jawaban Julien.
Letharion
8
Ini bisa jadi masalah. Sebagai contoh: Saya memiliki nama bidang (255) dan menambahkan unik ke bidang ini di nama (191) karena saya menggunakan utf8mb4. Jika saya memiliki pengguna saya tambahkan nama mereka dengan 'IJUE3ump5fiUuCi16jSofYS234MLschW4wsIktKiBrTPOTKBK6Vteh5pNuz1tKjy ... aO500mlJs' Dan pengguna lain menambahkan nama mereka dengan ini 'IJUE3ump5fiKuBiJUjAkUjAkUjAkUjAmA Itu harus melewati validasi tidak terjebak di entri duplikat.
vee
28
Batas indeks adalah 767 byte , bukan karakter. Dan karena utf8mb4set karakter Mysql (yang oleh seluruh dunia disebut utf8) membutuhkan (paling banyak) 4 byte per karakter Anda hanya dapat mengindeks hingga VARCHAR(191). utf8Kumpulan karakter Mysql (yang oleh sebagian besar dunia disebut rusak) membutuhkan paling banyak 3 byte per karakter jadi jika Anda menggunakannya (yang tidak seharusnya ), Anda dapat mengindeks hinggaVARCHAR(255)
Stijn de Witt
404

Jika ada yang mengalami masalah dengan INNODB / Utf-8 mencoba menempatkan UNIQUEindeks pada VARCHAR(256)bidang, alihkan ke VARCHAR(255). Tampaknya 255 adalah batasannya.

PinkTurtle
sumber
247
Jumlah karakter yang diizinkan tergantung pada set karakter Anda. UTF8 dapat menggunakan hingga 3 byte per karakter, utf8mb4 hingga 4 byte, dan latin1 hanya 1 byte. Jadi untuk utf8 panjang kunci Anda dibatasi hingga 255 karakter 3*255 = 765 < 767.
Stefan Endrullis
10
Ini menyelamatkan saya dari banyak frustrasi - terima kasih. Itu harus menjadi jawaban yang diterima IMO, mengingat pengguna menggunakan InnoDB dengan mengklaim mereka mencapai batasan 767b.
TheCarver
8
AS Stefan Endrullis menyatakan, itu tergantung pada rangkaian karakter. Jika Anda menggunakan UTF8 yang menggunakan 3 byte: 255x3 = 765 yang lebih rendah dari batas 767, sementara 256x3 = 768 yang lebih tinggi. Tetapi jika Anda menggunakan UTF8mb4-nya 255 * 4 = 1020, jadi ini bukan solusi yang benar-benar
bernhardh
25
Jawaban ini benar. Namun jika 255 benar-benar bekerja untuk Anda, itu berarti Anda menggunakan Mysql utf8, yang sayangnya rusak. Itu hanya dapat menyandikan karakter dalam bidang multibahasa dasar. Anda akan mendapatkan masalah dengan karakter yang berada di luar itu. Misalnya karakter Emoji yang telah mereka tambahkan berada di luarnya, kurasa. Jadi, alih-alih beralih ke VARCHAR(255), beralih ke VARCHAR(191) dan beralih ke pengkodean utf8mb4(yang sebenarnya hanya utf8, tetapi MySql ingin tetap kembali. Compat).
Stijn de Witt
1
Tidak membantu untuk kendala unik multicolumn saya. Ini juga tidak akan berfungsi untuk kendala unik multicolumn OP. (akan memberikan ukuran total 825 byte)
Barett
351

Ketika Anda mencapai batas. Tetapkan yang berikut ini.

  • INNODB utf8 VARCHAR(255)
  • INNODB utf8mb4 VARCHAR(191)
Aley
sumber
34
Ini jawaban terbaik. Sederhana, langsung ke intinya dan juga termasuk utf8mb4batas (yang merupakan pengkodean yang paling banyak digunakan untuk database yang lebih baru, karena ia menerima emoji / etc).
Claudio Holanda
10
karena 767/4 ~ = 191, dan 767/3 ~ = 255
Akuntan
11
di mana dan bagaimana mengaturnya?
Dinesh Sunny
1
Ya, dengan menentukan ENGINE=InnoDB DEFAULT CHARSET=utf8pada akhir CREATE TABLEpernyataan saya dapat memiliki VARCHAR(255)kunci utama. Terima kasih.
xonya
1
seseorang memberinya +1 untuk melampaui batas 191 :)
cagcak
147

MySQL mengasumsikan kasus terburuk untuk jumlah byte per karakter dalam string. Untuk pengkodean 'utf8' MySQL, itu 3 byte per karakter karena pengkodean itu tidak memungkinkan karakter di luar U+FFFF. Untuk pengkodean MySQL 'utf8mb4', ini berukuran 4 byte per karakter, karena itulah yang disebut MySQL sebagai UTF-8 sebenarnya.

Jadi dengan asumsi Anda menggunakan 'utf8', kolom pertama Anda akan mengambil 60 byte indeks, dan yang kedua 1500 lainnya.

morganwahl
sumber
4
- Yang mungkin berarti bahwa ketika menggunakan utf8mb4, saya perlu mengaturnya ke (paling banyak) 191 sebagai 191 * 4 = 764 <767.
Isaac
2
@ Isaac Ya, persis,
morganwahl
2
Saya pikir ini mungkin jawaban yang tepat, tetapi bisakah Anda menguraikan apa yang perlu dilakukan seseorang untuk memperbaiki masalah tersebut? Setidaknya untuk noobs MySQL seperti saya?
Adam Grant
Tidak ada satu cara untuk menyiasati batas indeks ini. Pertanyaannya di sini adalah tentang batasan unik; untuk itu, Anda dapat memiliki satu kolom teks panjang tak terbatas, dan lainnya di mana Anda menyimpan hash (seperti MD5) teks itu, dan menggunakan kolom hash untuk kendala unik Anda. Anda harus memastikan bahwa program Anda selalu memperbarui hash saat mengubah teks, tetapi ada berbagai cara untuk mengatasinya tanpa terlalu banyak kesulitan. Sejujurnya, MySQL harus mengimplementasikan hal seperti itu sendiri sehingga Anda tidak perlu; Saya tidak akan terkejut jika MariaDB memiliki sesuatu seperti itu built-in.
morganwahl
Indeks unik pada kolom varchar yang sangat panjang jarang terjadi. Pikirkan mengapa Anda membutuhkannya karena itu mungkin masalah desain. Jika Anda hanya menginginkan indeks untuk pencarian, pertimbangkan beberapa bidang 'kata kunci' yang sesuai dengan 191 karakter, atau bagi teks menjadi deskripsi pendek dan panjang / lengkap dll. Atau jika Anda benar-benar membutuhkan pencarian teks lengkap, pertimbangkan untuk menggunakan perangkat lunak khusus untuk itu, seperti Apache Lucene.
Stijn de Witt
56

jalankan kueri ini sebelum kueri Anda:

SET @@global.innodb_large_prefix = 1;

ini akan meningkatkan batas 3072 bytes.

Raza Ahmed
sumber
4
Apakah ada kerugian untuk mengubah ke innodb_large_prefix secara global? Dan apakah DB itu "global" atau semua DB yang BENAR-BENAR GLOBAL?
SciPhi
5
Hanya berlaku ketika menggunakan format baris non-standar. Lihat dev.mysql.com/doc/refman/5.5/en/… . Secara khusus, 'Aktifkan opsi ini untuk memungkinkan awalan kunci indeks yang lebih panjang dari 767 byte (hingga 3072 byte), untuk tabel InnoDB yang menggunakan format baris DYNAMIC dan COMPRESSED.' Format baris default tidak terpengaruh.
Chris Lear
5
Ini bekerja dengan baik untuk saya - detail lebih lanjut dan panduan dapat ditemukan di sini: mechanics.flite.com/blog/2014/07/29/…
cwd
1
apakah kita perlu me-restart server mysql setelah ini?
SimpleGuy
7
Detail penting yang hilang dari jawaban ini. innodb_file_formatharus BARRACUDAdan Pada level tabel Anda harus menggunakan ROW_FORMAT=DYNAMICatau ROW_FORMAT=COMPRESSED. Lihat komentar @ cwd di atas dengan panduan ini.
q0rban
46

Solusi Untuk Kerangka Laravel

Sesuai Laravel 5.4. * Dokumentasi ; Anda harus mengatur panjang string default di dalam bootmetode app/Providers/AppServiceProvider.phpfile sebagai berikut:

use Illuminate\Support\Facades\Schema;

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

Penjelasan perbaikan ini, diberikan oleh Laravel 5.4. * Dokumentasi :

Laravel menggunakan utf8mb4karakter yang ditetapkan secara default, yang mencakup dukungan untuk menyimpan "emoji" dalam database. Jika Anda menjalankan versi MySQL yang lebih lama dari rilis 5.7.7 atau MariaDB yang lebih lama dari rilis 10.2.2, Anda mungkin perlu mengkonfigurasi secara manual panjang string default yang dihasilkan oleh migrasi agar MySQL dapat membuat indeks untuk mereka. Anda dapat mengonfigurasi ini dengan memanggil Schema::defaultStringLengthmetode di dalam AppServiceProvider.

Atau, Anda dapat mengaktifkan innodb_large_prefixopsi untuk basis data Anda. Lihat dokumentasi database Anda untuk instruksi tentang cara mengaktifkan opsi ini dengan benar.

Ali Shaukat
sumber
10
@ BojanPetkovic, saya baru saja datang dari masalah Laravel, dan jawaban ini benar-benar menyelesaikan masalah saya.
mkmnstr
Jawaban ini bagus. Tetapi apakah ada yang tahu, mengapa ini bekerja?
UeliDeSchwert
1
Dokumentasi @Bobby Laravel memberikan penjelasannya dalam tajuk "Panjang Indeks & MySQL / MariaDB" laravel.com/docs/5.4/migrations#creating-indexes
Ali Shaukat
1
@ Bob Saya telah memperbarui jawabannya. Saya telah menambahkan penjelasan yang diberikan oleh dokumentasi laravel untuk perbaikan ini.
Ali Shaukat
39

Pengodean karakter apa yang Anda gunakan? Beberapa set karakter (seperti UTF-16, dan lain-lain) menggunakan lebih dari satu byte per karakter.

Amber
sumber
8
Jika itu UTF8, karakter dapat menggunakan hingga 4 byte, sehingga 20 kolom karakter 20 * 4 + 1byte, dan kolom 500 char 500 * 4 + 2byte
Thanatos
5
Untuk apa nilainya, saya hanya punya masalah yang sama dan beralih dari utf8_general_ci ke utf8_unicode_ci memecahkan masalah bagi saya. Saya tidak tahu mengapa :(
Andresch Serj
11
Untuk VARCHAR(256)kolom dengan UNIQUEindeks, mengubah susunan tidak berpengaruh bagi saya, seperti yang terjadi pada @Andresch. Namun, mengurangi panjang dari 256 ke 255 memang menyelesaikannya. Saya tidak mengerti mengapa, karena 767 / maks. 4 byte per karakter akan menghasilkan maksimal 191?
Arjan
10
255*3 = 765; 256*3 = 768. Tampaknya server Anda mengasumsikan 3 byte per karakter, @Arjan
Amber
21
@Reg: Anda benar, tetapi ini harus dijabarkan: UTF-8 sendiri menggunakan 1-4 byte per titik kode. "Kumpulan karakter" MySQL (benar-benar penyandian) memiliki rangkaian karakter yang disebut "utf8" yang mampu meng-enkode beberapa UTF-8, dan menggunakan 1-3 byte per titik kode, dan tidak mampu melakukan pengkodean titik kode di luar BMP. Ini juga mencakup set karakter lain yang disebut "utf8mb4", yang menggunakan 1-4 byte per titik kode, dan mampu mengkodekan semua titik kode Unicode. (utf8mb4 adalah UTF-8, utf8 adalah versi aneh dari UTF-8.)
Thanatos
28

Saya pikir varchar (20) hanya membutuhkan 21 byte sementara varchar (500) hanya membutuhkan 501 byte. Jadi total byte adalah 522, kurang dari 767. Jadi mengapa saya mendapatkan pesan kesalahan?

UTF8 membutuhkan 3 byte per karakter untuk menyimpan string, jadi dalam kasus Anda 20 + 500 karakter = 20 * 3 + 500 * 3 = 1560 byte yang lebih dari yang diizinkan 767 byte.

Batas untuk UTF8 adalah 767/3 = 255 karakter , untuk UTF8mb4 yang menggunakan 4 byte per karakter adalah 767/4 = 191 karakter.


Ada dua solusi untuk masalah ini jika Anda perlu menggunakan kolom yang lebih panjang dari batas:

  1. Gunakan pengkodean "lebih murah" (yang membutuhkan byte lebih sedikit per karakter)
    Dalam kasus saya, saya perlu menambahkan indeks unik pada kolom yang berisi string artikel SEO, karena saya hanya menggunakan [A-z0-9\-]karakter untuk SEO, saya menggunakan latin1_general_ciyang hanya menggunakan satu byte per karakter dan kolom dapat memiliki panjang 767 byte.
  2. Buat hash dari kolom Anda dan gunakan indeks unik hanya pada itu
    . Pilihan lain bagi saya adalah membuat kolom lain yang akan menyimpan hash SEO, kolom ini akan memiliki UNIQUEkunci untuk memastikan nilai SEO unik. Saya juga akan menambahkan KEYindeks ke kolom SEO asli untuk mempercepat pencarian.
Buksy
sumber
Ini berhasil. Saya sudah memiliki varchar (256) dan saya harus mengubahnya ke varchar (250).
MaRmAR
25

Jawaban tentang mengapa Anda mendapatkan pesan kesalahan sudah dijawab oleh banyak pengguna di sini. Jawaban saya adalah tentang cara memperbaiki dan menggunakannya sebagaimana mestinya.

Rujuk dari tautan ini .

  1. Buka klien MySQL (atau klien MariaDB). Ini adalah alat baris perintah.
  2. Ini akan menanyakan kata sandi Anda, masukkan kata sandi Anda yang benar.
  3. Pilih database Anda dengan menggunakan perintah ini use my_database_name;

Basis data berubah

  1. set global innodb_large_prefix=on;

Kueri OK, 0 baris terpengaruh (0,00 dtk)

  1. set global innodb_file_format=Barracuda;

Kueri OK, 0 baris terpengaruh (0,02 dtk)

  1. Pergi ke database Anda di phpMyAdmin atau sesuatu seperti itu untuk manajemen mudah > Pilih database> Lihat struktur tabel > Buka tab Operasi . > Ubah ROW_FORMAT menjadi DYNAMIC dan simpan perubahan.
  2. Buka tab struktur tabel > Klik tombol Unik .
  3. Selesai Sekarang seharusnya tidak ada kesalahan.

Masalah perbaikan ini adalah jika Anda mengekspor db ke server lain (misalnya dari localhost ke host nyata) dan Anda tidak dapat menggunakan baris perintah MySQL di server itu. Anda tidak dapat membuatnya bekerja di sana.

vee
sumber
jika Anda masih galat setelah memasukkan kueri di atas, coba buka "phpmyadmin"> setel "collation" ke preferensi Anda (bagi saya saya menggunakan "utf8_general_ci")> klik apply (walaupun sudah utf8)
Anthony Kal
Saya tidak menggunakan alat yang berfungsi dengan instruksi Anda, tetapi saya masih memberikan suara untuk mencoba membantu orang dengan benar - benar memperbaiki masalah. Ada banyak sekali penjelasan tentang apa yang menyebabkan masalah, tetapi sangat sedikit tentang bagaimana sebenarnya menyelesaikannya.
Teekin
20
Specified key was too long; max key length is 767 bytes

Anda mendapat pesan itu karena 1 byte sama dengan 1 karakter hanya jika Anda menggunakan latin-1set karakter. Jika Anda menggunakan utf8, setiap karakter akan dianggap 3 byte ketika mendefinisikan kolom kunci Anda. Jika Anda menggunakan utf8mb4, setiap karakter akan dianggap 4 byte ketika mendefinisikan kolom kunci Anda. Jadi, Anda perlu mengalikan batas karakter bidang kunci Anda dengan, 1, 3, atau 4 (dalam contoh saya) untuk menentukan jumlah byte yang ingin diizinkan oleh bidang kunci. Jika Anda menggunakan uft8mb4, Anda hanya dapat menentukan 191 karakter untuk bidang asli, InnoDB, kunci utama. Hanya saja, jangan melanggar 767 byte.

Anthony Rutledge
sumber
17

Ganti utf8mb4dengan utf8dalam file impor Anda.

masukkan deskripsi gambar di sini

Bryan
sumber
Mengapa orang harus melakukan itu? Selain itu, jika ini memiliki kerugian (yang saya asumsikan), Anda harus menyebutkan ini
Nico Haase
16

Anda bisa menambahkan kolom dari md5 kolom yang panjang

diyism
sumber
Perhatikan bahwa ini tidak akan memungkinkan Anda untuk melakukan pemindaian jarak pada kolom-kolom ini. Panjang awalan pada VARCHAR akan memungkinkan Anda untuk mempertahankan sifat ini, sambil menyebabkan kemungkinan kecocokan palsu dalam indeks (dan pemindaian dan pencarian baris untuk menghilangkannya) (lihat jawaban yang diterima). (Ini pada dasarnya adalah indeks hash yang diimplementasikan secara manual, yang sayangnya MysQL tidak mendukung dengan tabel InnoDB.)
Thanatos
Saya tidak bisa menggunakan indeks awalan karena saya perlu menjaga kompatibilitas dengan H2 untuk tujuan pengujian, dan menemukan menggunakan kolom hash berfungsi dengan baik. Saya akan sangat menyarankan menggunakan fungsi tahan tabrakan seperti SHA1, bukan MD5 untuk mencegah pengguna jahat membuat tabrakan. Tabrakan indeks dapat dieksploitasi untuk membocorkan data jika salah satu pertanyaan Anda hanya memeriksa nilai hash, dan bukan nilai kolom penuh.
Little Mike
13

Kami mengalami masalah ini ketika mencoba menambahkan indeks UNIQUE ke bidang VARCHAR (255) menggunakan utf8mb4. Sementara masalahnya sudah diuraikan dengan baik di sini, saya ingin menambahkan beberapa saran praktis tentang cara kami memecahkan masalah ini dan menyelesaikannya.

Saat menggunakan utf8mb4, karakter dihitung sebagai 4 byte, sedangkan di bawah utf8, mereka dapat sebagai 3 byte. Database InnoDB memiliki batas bahwa indeks hanya dapat berisi 767 byte. Jadi ketika menggunakan utf8, Anda dapat menyimpan 255 karakter (767/3 = 255), tetapi menggunakan utf8mb4, Anda hanya dapat menyimpan 191 karakter (767/4 = 191).

Anda benar-benar dapat menambahkan indeks reguler untuk VARCHAR(255)bidang menggunakan utf8mb4, tetapi yang terjadi adalah ukuran indeks dipotong pada 191 karakter secara otomatis - seperti di unique_keysini:

Tangkapan layar Sequel Pro menunjukkan indeks terpotong pada 191 karakter

Ini bagus, karena indeks reguler hanya digunakan untuk membantu pencarian MySQL melalui data Anda lebih cepat. Seluruh bidang tidak perlu diindeks.

Jadi, mengapa MySQL memotong indeks secara otomatis untuk indeks reguler, tetapi melemparkan kesalahan eksplisit ketika mencoba melakukannya untuk indeks unik? Nah, agar MySQL dapat mengetahui apakah nilai yang dimasukkan atau diperbarui sudah ada, perlu benar-benar mengindeks seluruh nilai dan bukan hanya sebagian saja.

Pada akhir hari, jika Anda ingin memiliki indeks unik pada suatu bidang, seluruh isi bidang harus sesuai dengan indeks. Untuk utf8mb4, ini berarti mengurangi panjang bidang VARCHAR Anda menjadi 191 karakter atau kurang. Jika Anda tidak membutuhkan utf8mb4 untuk tabel atau bidang itu, Anda bisa mengembalikannya ke utf8 dan dapat mempertahankan bidang 255 panjang Anda.

maknz
sumber
11

Inilah jawaban asli saya:

Saya hanya menjatuhkan basis data dan membuat ulang seperti ini, dan kesalahannya hilang:

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

Namun, itu tidak berfungsi untuk semua kasus.

Ini sebenarnya masalah menggunakan indeks pada kolom VARCHAR dengan set karakter utf8(atau utf8mb4), dengan kolom VARCHAR yang memiliki lebih dari panjang karakter tertentu. Dalam kasus utf8mb4, panjang tertentu adalah 191.

Silakan merujuk ke bagian Indeks Panjang dalam artikel ini untuk informasi lebih lanjut bagaimana menggunakan indeks panjang dalam database MySQL: http://hanoian.com/content/index.php/24-automate-the-converting-a-mysql-database- character-set-to-utf8mb4

Châu Hồng Lĩnh
sumber
Memecahkan masalah untuk pengaturan openmeetings (BTW Anda menyelamatkan malam saya :-)
Ludo
11

5 solusi:

Batas dinaikkan di 5.7.7 (MariaDB 10.2.2?). Dan itu dapat ditingkatkan dengan beberapa pekerjaan di 5.6 (10.1).

Jika Anda mencapai batas karena mencoba menggunakan CHARACTER SET utf8mb4. Kemudian lakukan salah satu dari yang berikut (masing-masing memiliki kelemahan) untuk menghindari kesalahan:

  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

Rick James
sumber
10

Saya memperbaiki masalah ini dengan:

varchar(200) 

digantikan dengan

varchar(191)

semua varchar yang memiliki lebih dari 200 menggantinya dengan 191 atau mengaturnya teks.

flik
sumber
Ini juga yang bekerja untuk saya. Saya punya varchar (250), tetapi datanya tidak pernah selama itu. Mengubahnya menjadi varchar (100). Terima kasih untuk idenya :)
Arun Basil Lal
7

Saya melakukan pencarian pada topik ini akhirnya mendapat beberapa perubahan kustom

Untuk MySQL workbench 6.3.7 Versi Antar fase grafis tersedia

  1. Mulai Workbench dan pilih koneksi.
  2. Buka manajemen atau Instance dan pilih Opsi File.
  3. Jika Workbench meminta Anda untuk membaca file konfigurasi dan kemudian mengizinkannya dengan menekan OK dua kali.
  4. Di pusat tempat, jendela file opsi Administrator datang.
  5. Buka tab InnoDB dan periksa innodb_large_prefix jika tidak dicentang di bagian Umum.
  6. set nilai opsi innodb_default_row_format ke DYNAMIC.

Untuk Versi di bawah 6.3.7 opsi langsung tidak tersedia sehingga perlu pergi dengan command prompt

  1. Mulai CMD sebagai administrator.
  2. Pergi ke direktur tempat server mysql diinstal Sebagian besar kasus di "C: \ Program Files \ MySQL \ MySQL Server 5.7 \ bin" jadi perintahnya adalah "cd \" "cd Program Files \ MySQL \ MySQL Server 5.7 \ bin".
  3. Sekarang Jalankan perintah mysql -u userName -p databasescheema Sekarang ia meminta kata sandi dari masing-masing pengguna. Berikan kata sandi dan masukkan ke prompt mysql.
  4. Kita harus mengatur beberapa pengaturan global, masukkan perintah di bawah ini satu per satu, set global innodb_large_prefix = on; atur global innodb_file_format = barracuda; set global innodb_file_per_table = true;
  5. Sekarang pada akhirnya kita harus mengubah ROW_FORMAT dari tabel yang diperlukan secara default COMPACT-nya kita harus mengaturnya menjadi DINAMIK.
  6. gunakan perintah berikut mengubah table table_name ROW_FORMAT = DYNAMIC;
  7. Selesai
Abhishek
sumber
Saya tidak dapat menemukan ini: 6. set nilai opsi innodb_default_row_format ke DYNAMIC.
Adrian Cid Almaguer
jika saya menggunakan, set global innodb_default_row_format = DYNAMIC;saya melihat pesan ini: ERROR 1193 (HY000): Variabel sistem tidak dikenal 'innodb_default_row_format'
Adrian Cid Almaguer
bagaimana Anda mendapat kesalahan dari workbench ke cmd? Saya melakukannya dari meja kerja yang memiliki opsi langsung.
Abhishek
Saya melakukannya dari CMD karena saya tidak melihat opsi di Workbench
Adrian Cid Almaguer
1
Saya melihat masalah var ini diperkenalkan di v5.7.9 dan saya memiliki versi v5.6.33, terima kasih
Adrian Cid Almaguer
7

Untuk laravel 5.7 hingga 6.0

Langkah yang harus diikuti

  1. Pergi ke App\Providers\AppServiceProvider.php.
  2. Tambahkan ini ke penyedia use Illuminate\Support\Facades\Schema;di atas.
  3. Di dalam fungsi Boot Tambahkan ini Schema::defaultStringLength(191);

itu saja, Selamat menikmati.

Manojkiran.A
sumber
Bekerja untuk Laravel 5.8 juga.
Neo
Ini solusi yang buruk. Alasan: indeks tidak dimaksudkan untuk panjang tak terhingga. Ketika Anda menerapkan indeks unik untuk sesuatu, Anda ingin indeks untuk memperbaiki sebagian besar waktu. Itu berarti Anda TIDAK HARUS membuat hal-hal seperti emailunik, tetapi Anda harus hash email dan menjadikannya unik. Tidak seperti data string-baku, hash memiliki lebar tetap dan dapat diindeks dan dibuat unik tanpa masalah. Alih-alih memahami masalahnya, Anda justru menyebarkan praktik-praktik mengerikan yang tidak berkembang.
NB
5

ubah susunan Anda. Anda dapat menggunakan utf8_general_ci yang mendukung hampir semua

Nids Barthwal
sumber
"Hampir" adalah petunjuk yang cukup bagus bahwa ini bukan solusi jangka panjang
Nico Haase
4

Hanya mengubah utf8mb4ke utf8saat membuat tabel memecahkan masalah saya. Misalnya: CREATE TABLE ... DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;untuk CREATE TABLE ... DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;.

MajidJafari
sumber
4

Untuk memperbaikinya, ini bekerja untuk saya seperti pesona.

ALTER DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;
Nick Pridorozhko
sumber
Saya mengkonfirmasi bahwa masalah saya adalah pengumpulan basis data juga. Saya tidak punya penjelasan untuk itu. Saya menggunakan mysql v5.6.32 dan DB collation adalah utf8mb4_unicode_ci.
Mahyard
2

Berdasarkan kolom yang diberikan di bawah ini, 2 kolom string variabel menggunakan utf8_general_cicollation ( utf8charset tersirat).

Di MySQL, utf8charset menggunakan maksimal 3 byte untuk setiap karakter. Dengan demikian, perlu mengalokasikan 500 * 3 = 1500 byte, yang jauh lebih besar dari 767 byte yang diizinkan MySQL. Itu sebabnya Anda mendapatkan kesalahan 1071 ini.

Dengan kata lain, Anda perlu menghitung jumlah karakter berdasarkan representasi byte charset karena tidak setiap charset adalah representasi byte tunggal (seperti yang Anda duga.) IE utf8dalam MySQL paling banyak menggunakan 3-byte per karakter, 767 / 3≈255 karakter, dan untuk utf8mb4, paling banyak 4 byte representasi, 767/4191 karakter.

Juga diketahui bahwa MySQL

column1 varchar(20) utf8_general_ci
column2  varchar(500) utf8_general_ci
Devy
sumber
1

Saya menemukan kueri ini berguna dalam mendeteksi kolom mana yang memiliki indeks yang melanggar panjang maks:

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')
Andrew
sumber
1

Silakan periksa apakah sql_modesuka

sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

jika ya, ubah ke

sql_mode=NO_ENGINE_SUBSTITUTION

ATAU

restart server Anda mengubah file my.cnf Anda (dengan mengikuti)

innodb_large_prefix=on
neel
sumber
1

Dalam kasus saya, saya mengalami masalah ini ketika saya mencadangkan database menggunakan karakter redirection output / input linux. Oleh karena itu, saya mengubah sintaks seperti yang dijelaskan di bawah ini. PS: menggunakan terminal linux atau mac.

Cadangkan (tanpa> redirect)

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

Pulihkan (tanpa <redirect)

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

Kesalahan "kunci yang ditentukan terlalu panjang; panjang kunci maks adalah 767 byte" sederhana menghilang.

Cassio Seffrin
sumber
1

Panjang Indeks & MySQL / MariaDB


Laravel menggunakan karakter utf8mb4 yang ditetapkan secara default, yang mencakup dukungan untuk menyimpan "emoji" dalam database. Jika Anda menjalankan versi MySQL yang lebih lama dari rilis 5.7.7 atau MariaDB yang lebih lama dari rilis 10.2.2, Anda mungkin perlu mengkonfigurasi secara manual panjang string default yang dihasilkan oleh migrasi agar MySQL dapat membuat indeks untuk mereka. Anda dapat mengonfigurasikan ini dengan memanggil metode Schema :: defaultStringLength di dalam AppServiceProvider Anda :

use Illuminate\Support\Facades\Schema;

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

Atau, Anda dapat mengaktifkan opsi innodb_large_prefix untuk database Anda. Lihat dokumentasi database Anda untuk instruksi tentang cara mengaktifkan opsi ini dengan benar.

Referensi dari blog: https://www.scratchcode.io/specified-key-too-long-error-in-laravel/

Referensi dari dokumentasi resmi laravel: https://laravel.com/docs/5.7/migrations

Mayank Dudakiya
sumber
0

Jika Anda membuat sesuatu seperti:

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;

harus seperti itu

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;

tetapi Anda perlu memeriksa keunikan kolom itu dari kode atau menambahkan kolom baru sebagai MD5 atau SHA1 dari kolom varchar

10 pengguna
sumber
3
Kemudian kunci unik Anda hilang. Saya pikir cara yang lebih baik adalah dengan mengurangi panjang nama menjadi 191.
haudoing
1
Mengapa harus memeriksa keunikan secara terprogram jika itu fitur DB asli?
Paweł Tomkiel
0

Karena keterbatasan awalan kesalahan ini akan terjadi. 767 byte adalah batasan awalan yang dinyatakan untuk tabel InnoDB dalam versi MySQL sebelum 5.7. Panjangnya 1.000 byte untuk tabel MyISAM. Dalam versi MySQL 5.7 dan ke atas batas ini telah ditingkatkan menjadi 3072 byte.

Menjalankan hal berikut pada layanan yang memberi Anda kesalahan harus menyelesaikan masalah Anda. Ini harus dijalankan di MYSQL CLI.

SET GLOBAL innodb_file_format=Barracuda;
SET GLOBAL innodb_file_per_table=on;
SET GLOBAL innodb_large_prefix=on;
Sungai
sumber
-1

Ubah CHARSET dari bidang indeks yang mengeluh ke "latin1"
yaitu ALTER TABLE tbl CHANGE myfield myfield varchar (600) SET KARAKTER latin1 DEFAULT NULL;
latin1 mengambil satu byte untuk satu karakter, bukan empat

Stan Holodnak
sumber
5
Dan bagaimana jika dia akan mencoba memasukkan karakter non-latin1 ?
Paweł Tomkiel
4
Ini adalah hal terburuk yang harus dilakukan. Tidak pernah melakukannya.
Sebas
1
dalam kasus saya ini pada kolom yang menyimpan nama jalur dengan hanya karakter hex ... jadi ini mungkin solusi untuk seseorang. itu benar-benar tergantung pada apa yang ingin Anda simpan ...
codewandler
Saya harus menghapus ini, karena menggunakan latin1 bukan solusi di 2016AD. Saya masih memiliki mimpi buruk yang mengerikan tentang waktu kami harus mengkonversi database dari latin1 ke utf8 kembali pada tahun 2007. Ugh. Tidak cantik. Sama sekali.
Taruhan Lamed
Saya memiliki masalah yang sama pada indeks unik pada dua kolom tempat saya menyimpan alamat bitcoin dan ID transaksi. Ini akan selalu menjadi karakter ASCII, jadi saya akan menggunakan latin1 pada kolom ini. Upvoting.
alexg
-2

Jika Anda innodb_log_file_sizebaru saja berubah , cobalah untuk mengembalikan nilai sebelumnya yang berfungsi.

YaituK
sumber