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
mysql
byte
varchar
mysql-error-1071
Steven
sumber
sumber
Jawaban:
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:
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.
sumber
utf8mb4
set karakter Mysql (yang oleh seluruh dunia disebut utf8) membutuhkan (paling banyak) 4 byte per karakter Anda hanya dapat mengindeks hinggaVARCHAR(191)
.utf8
Kumpulan 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)
Jika ada yang mengalami masalah dengan INNODB / Utf-8 mencoba menempatkan
UNIQUE
indeks padaVARCHAR(256)
bidang, alihkan keVARCHAR(255)
. Tampaknya 255 adalah batasannya.sumber
3*255 = 765 < 767
.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 keVARCHAR(255)
, beralih keVARCHAR(191)
dan beralih ke pengkodeanutf8mb4
(yang sebenarnya hanya utf8, tetapi MySql ingin tetap kembali. Compat).Ketika Anda mencapai batas. Tetapkan yang berikut ini.
utf8
VARCHAR(255)
utf8mb4
VARCHAR(191)
sumber
utf8mb4
batas (yang merupakan pengkodean yang paling banyak digunakan untuk database yang lebih baru, karena ia menerima emoji / etc).ENGINE=InnoDB DEFAULT CHARSET=utf8
pada akhirCREATE TABLE
pernyataan saya dapat memilikiVARCHAR(255)
kunci utama. Terima kasih.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.
sumber
jalankan kueri ini sebelum kueri Anda:
ini akan meningkatkan batas
3072 bytes
.sumber
innodb_file_format
harusBARRACUDA
dan Pada level tabel Anda harus menggunakanROW_FORMAT=DYNAMIC
atauROW_FORMAT=COMPRESSED
. Lihat komentar @ cwd di atas dengan panduan ini.Solusi Untuk Kerangka Laravel
Sesuai Laravel 5.4. * Dokumentasi ; Anda harus mengatur panjang string default di dalam
boot
metodeapp/Providers/AppServiceProvider.php
file sebagai berikut:Penjelasan perbaikan ini, diberikan oleh Laravel 5.4. * Dokumentasi :
sumber
Pengodean karakter apa yang Anda gunakan? Beberapa set karakter (seperti UTF-16, dan lain-lain) menggunakan lebih dari satu byte per karakter.
sumber
20 * 4 + 1
byte, dan kolom 500 char500 * 4 + 2
byteVARCHAR(256)
kolom denganUNIQUE
indeks, 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?255*3 = 765; 256*3 = 768
. Tampaknya server Anda mengasumsikan 3 byte per karakter, @ArjanUTF8 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:
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 menggunakanlatin1_general_ci
yang hanya menggunakan satu byte per karakter dan kolom dapat memiliki panjang 767 byte.. Pilihan lain bagi saya adalah membuat kolom lain yang akan menyimpan hash SEO, kolom ini akan memiliki
UNIQUE
kunci untuk memastikan nilai SEO unik. Saya juga akan menambahkanKEY
indeks ke kolom SEO asli untuk mempercepat pencarian.sumber
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 .
use my_database_name;
set global innodb_large_prefix=on;
set global innodb_file_format=Barracuda;
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.
sumber
Anda mendapat pesan itu karena 1 byte sama dengan 1 karakter hanya jika Anda menggunakan
latin-1
set karakter. Jika Anda menggunakanutf8
, setiap karakter akan dianggap 3 byte ketika mendefinisikan kolom kunci Anda. Jika Anda menggunakanutf8mb4
, 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.sumber
Ganti
utf8mb4
denganutf8
dalam file impor Anda.sumber
Anda bisa menambahkan kolom dari md5 kolom yang panjang
sumber
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 diunique_key
sini: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.
sumber
Inilah jawaban asli saya:
Namun, itu tidak berfungsi untuk semua kasus.
Ini sebenarnya masalah menggunakan indeks pada kolom VARCHAR dengan set karakter
utf8
(atauutf8mb4
), dengan kolom VARCHAR yang memiliki lebih dari panjang karakter tertentu. Dalam kasusutf8mb4
, 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
sumber
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:
- http://mysql.rjweb.org/doc.php/limits#767_limit_in_innodb_indexes
sumber
Saya memperbaiki masalah ini dengan:
digantikan dengan
semua varchar yang memiliki lebih dari 200 menggantinya dengan 191 atau mengaturnya teks.
sumber
Saya melakukan pencarian pada topik ini akhirnya mendapat beberapa perubahan kustom
Untuk MySQL workbench 6.3.7 Versi Antar fase grafis tersedia
Untuk Versi di bawah 6.3.7 opsi langsung tidak tersedia sehingga perlu pergi dengan command prompt
sumber
set global innodb_default_row_format = DYNAMIC;
saya melihat pesan ini: ERROR 1193 (HY000): Variabel sistem tidak dikenal 'innodb_default_row_format'Untuk laravel 5.7 hingga 6.0
Langkah yang harus diikuti
App\Providers\AppServiceProvider.php
.use Illuminate\Support\Facades\Schema;
di atas.Schema::defaultStringLength(191);
itu saja, Selamat menikmati.
sumber
email
unik, 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.ubah susunan Anda. Anda dapat menggunakan utf8_general_ci yang mendukung hampir semua
sumber
Hanya mengubah
utf8mb4
keutf8
saat membuat tabel memecahkan masalah saya. Misalnya:CREATE TABLE ... DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
untukCREATE TABLE ... DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
.sumber
Untuk memperbaikinya, ini bekerja untuk saya seperti pesona.
sumber
Berdasarkan kolom yang diberikan di bawah ini, 2 kolom string variabel menggunakan
utf8_general_ci
collation (utf8
charset tersirat).Di MySQL,
utf8
charset 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
utf8
dalam MySQL paling banyak menggunakan 3-byte per karakter, 767 / 3≈255 karakter, dan untukutf8mb4
, paling banyak 4 byte representasi, 767/4191 karakter.Juga diketahui bahwa MySQL
sumber
Saya menemukan kueri ini berguna dalam mendeteksi kolom mana yang memiliki indeks yang melanggar panjang maks:
sumber
Silakan periksa apakah
sql_mode
sukajika ya, ubah ke
ATAU
restart server Anda mengubah file my.cnf Anda (dengan mengikuti)
sumber
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)
Pulihkan (tanpa <redirect)
Kesalahan "kunci yang ditentukan terlalu panjang; panjang kunci maks adalah 767 byte" sederhana menghilang.
sumber
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 :
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
sumber
Jika Anda membuat sesuatu seperti:
harus seperti itu
tetapi Anda perlu memeriksa keunikan kolom itu dari kode atau menambahkan kolom baru sebagai MD5 atau SHA1 dari kolom varchar
sumber
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.
sumber
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
sumber
Jika Anda
innodb_log_file_size
baru saja berubah , cobalah untuk mengembalikan nilai sebelumnya yang berfungsi.sumber