# 1071 - Belirtilen anahtar çok uzundu; maksimum anahtar uzunluğu 767 bayttır


562

Aşağıdaki komutu yürüttüğümde:

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

Bu hata mesajını aldım:

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

Sütun1 ve sütun2 hakkında bilgi:

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

Bence varchar(20)sadece 21 bayt, varchar(500)sadece 501 bayt gerektirir. Yani toplam bayt sayısı 522, 767'den az. Neden hata mesajını aldım?

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

5
520 bayt değil, 767 baytı aşan 2080 bayt olduğundan, sütun1 varchar (20) ve sütun2 varchar (170) yapabilirsiniz. Bir karakter / bayt eşdeğeri istiyorsanız, latin1
Rahly

3
Bence hesaplamanız burada biraz yanlış. mysql, uzunluk uzunluğunu kaydetmek için 1 veya 2 ekstra bayt kullanır: sütunun maksimum uzunluğu 255 bayt veya daha azsa 1 bayt, 255 bayttan uzunsa 2 bayt. utf8_general_ci kodlaması karakter başına 3 bayta ihtiyaç duyar, bu nedenle varchar (20) 61 bayt kullanır, varchar (500) toplam 1563
baytta

3
mysql> info_schema.character_sets öğesinden maxlen, character_set_name öğesini seçin (burada 'latin1', 'utf8', 'utf8mb4'); maxlen | karakter_etimi_adı ------ | ------------------- 1 | latin1 ------ | ------------------- 3 | utf8 ------ | ------------------- 4 | utf8mb4
lackovic10

15
'Bir karakter / bayt eşdeğeri istiyorsanız, latin1 kullanın' Lütfen bunu yapma . Latin1 gerçekten, gerçekten berbat. Bundan pişman olacaksın.
Stijn de Witt

Yanıtlar:


490

767 bayt, MySQL sürüm 5.6 (ve önceki sürümler) içindeki InnoDB tabloları için belirtilen önek sınırlamasıdır . MyISAM tabloları için 1.000 bayt uzunluğunda. MySQL 5.7 ve sonraki sürümlerde bu sınır 3072 bayta çıkarıldı.

Ayrıca, utf8mb4 kodlu büyük bir karakter veya varchar alanında bir dizin ayarlarsanız, 767 bayt (veya 3072 bayt) maksimum dizin önek uzunluğunu 191 ile sonuçlanan 4'e bölmeniz gerektiğini unutmayın. utf8mb4 karakterinin maksimum uzunluğu dört bayttır. Bir utf8 karakteri için üç bayt olur ve sonuçta maksimum dizin önek uzunluğu 254 olur.

Sahip olduğunuz seçeneklerden biri, VARCHAR alanlarınıza yalnızca alt sınır koymaktır.

Başka bir seçenek ( bu soruna verilen cevaba göre ), sütunun alt kümesini tutarın tamamı yerine almaktır, yani:

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

Uygulamak için anahtarı almanız gerektiğinde değiştirin, ancak MySQL sınırlamasına uymadan amaçlanan iş kurallarını uygulamanıza izin verecek iyileştirmeler olup olmadığını görmek için bu varlıkla ilgili veri modelinizi gözden geçirmenin buna değip değmeyeceğini merak ediyorum.


4
Miktarın tamamı yerine sütunun bir alt kümesini belirterek uygulamak için. İyi bir çözüm.
Steven

204
Bu, uzunluk sınırının altındaki alanların neden uzunluk sınırını aştığını açıklamıyor ...
Cerin

6
@Cerin yukarıda eksik olan bilgilerde düzenleme yapmayı denedim, bu da açıkça başkaları tarafından eksik olarak kabul edildi, ancak bir yorum olarak daha uygun olduğu reddedildi. Neden 500 + 20> 767'yi anlamaya çalışanlar için Stefan Endrullis'in Julien'in cevabı hakkındaki yorumuna bakın.
Letharion

8
Bu bir sorun olabilir. Örneğin: Alan adı (255) var ve utf8mb4 kullandığım için bu alana benzersiz bir isim (191) ekliyorum. Kullanıcılarımın adını 'IJUE3ump5fiUuCi16jSofYS234MLschW4wsIktKiBrTPOTKBK6Vteh5pNuz1tKjy ... aO500mlJs' ile ismimi eklersem ve diğer kullanıcı isimlerini bu 'IJUE3ump5fiUuCi16jSofYtwkWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKWKKK Yinelenen girişte sıkışmamış doğrulama geçmelidir.
vee

28
Dizin sınırı, karakterler değil 767 bayttır . Ve Mysql'in utf8mb4karakter setinin (dünyanın geri kalanı utf8 olarak adlandırdığı), karakter başına 4 bayta ihtiyaç duyduğu için sadece endeksleyebilirsiniz VARCHAR(191). MySQL'ın utf8bunu kullanıyor eğer öyleyse (dünyanın geri kalanı kırık aramaları) karakter kümesi karakter başına en fazla 3 bayt gerekmektedir (hangi olmamalıdır ) Burada yapabilecekleriniz endeksi yukarıVARCHAR(255)
Stijn de Witt

404

Herhangi bir kişi INNODB / Utf-8 UNIQUEile bir VARCHAR(256)alan üzerinde bir dizin koymaya çalışırken sorun yaşıyorsa , bunu değiştirin VARCHAR(255). Sınırlılık 255 gibi görünüyor.


247
İzin verilen karakter sayısı sadece karakter setinize bağlıdır. UTF8 karakter başına 3 bayta, utf8mb4 4 bayta kadar ve latin1 yalnızca 1 bayt kullanabilir. Böylece utf8 için anahtar uzunluğunuz 255 karakterle sınırlıdır 3*255 = 765 < 767.
Stefan Endrullis

10
Bu beni çok fazla hayal kırıklığına uğrattı - teşekkürler. Kullanıcı, 767b sınırlamalarına ulaştığını iddia ederek InnoDB kullandığını düşünerek kabul edilen cevap IMO olmalıdır.
TheCarver

8
Stefan Endrullis'in belirttiği gibi, karakter kümesine bağlı. 3 bayt kullanan UTF8 kullanırsanız: 255x3 = 765, 767 sınırından düşüktür; 256x3 = 768 daha yüksektir. Ama UTF8mb4 kullanıyorsanız onun 255 * 4 = 1020, bu yüzden gerçek bir çözüm değil
bernhardh

25
Bu cevap doğrudur. Ancak 255 eğer gerçekten sizin için çalışıyor, sizin Mysql kullanarak anlamına gelir utf8maalesef bozuldu. Yalnızca temel çok dilli düzlemdeki karakterleri kodlayabilir. Bunun dışında kalan karakterlerle ilgili sorunlar alırsınız. Örneğin, ekledikleri Emoji karakterleri bunun dışında kalıyor. Yani yerine geçmeyi VARCHAR(255)geçiş, VARCHAR(191) ve kodlamayı geçiş utf8mb4(aslında sadece utf8 olmakla MySql. COMPAT geri tutmak istedim).
Stijn de Witt

1
Çok sütunlu benzersiz kısıtlama için yararlı değil. Ayrıca OP'nin çok sütunlu benzersiz kısıtlaması için de işe yaramaz. (toplam boyutu 825 bayt verir)
Barett

351

Sınıra çarptığınızda. Aşağıdakileri ayarlayın.

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

34
Bu en iyi cevap. Basit, doğrudan noktaya ve aynı zamanda utf8mb4sınır içerir (emoji / vb. Kabul ettiği için daha yeni veritabanları için en çok kullanılan kodlamadır).
Claudio Holanda

10
çünkü 767/4 ~ = 191 ve 767/3 ~ = 255
Muhasebeci م

11
nerede ve nasıl ayarlanır?
Dinesh Sunny

1
Evet, ifadenin ENGINE=InnoDB DEFAULT CHARSET=utf8sonunda CREATE TABLEbir VARCHAR(255)birincil anahtara sahip olduğumu belirterek . Teşekkürler.
xonya

1
Birisi ona sınırı 191 aşmak için +1 vermek :)
cagcak

147

MySQL, dizedeki karakter başına bayt sayısı için en kötü durum olduğunu varsayar. MySQL 'utf8' kodlaması için, karakter başına 3 bayttır, çünkü kodlama ötesindeki karakterlere izin vermez U+FFFF. MySQL 'utf8mb4' kodlaması için, karakter başına 4 bayttır, çünkü MySQL gerçek UTF-8 olarak adlandırır.

'Utf8' kullandığınızı varsayarsak, ilk sütununuz dizinin 60 baytını, ikincinizin 1500 değerini alır.


4
- Bu muhtemelen utf8mb4 kullanırken, onları (en fazla) 191 olarak 191 * 4 = 764 <767 olarak ayarlamam gerektiği anlamına gelir.
Isaac

2
@Isaac Evet, aynen,
morganwahl

2
Bence bu doğru cevap olabilir, ancak böyle bir sorunu düzeltmek için ne yapmanız gerektiğini açıklayabilir misiniz? En azından benim gibi MySQL noobs için mi?
Adam Grant

Bu endeks sınırını aşmanın tek bir yolu yoktur. Buradaki soru benzersiz kısıtlamalar ile ilgilidir; bunlar için sınırsız uzunluktaki bir metin sütununa ve bu metnin bir karma değerini (MD5 gibi) sakladığınız ve benzersiz kısıtlamanız için karma sütununu kullanabileceğiniz bir sütuna sahip olabilirsiniz. Metninizi değiştirdiğinde programınızın karmaları güncel tutmasını sağlamanız gerekir, ancak bunu çok fazla sorun olmadan ele almanın çeşitli yolları vardır. Açıkçası, MySQL böyle bir şeyi kendisi uygulamalıdır, böylece zorunda değilsiniz; MariaDB'de böyle bir şey varsa şaşırmam.
morganwahl

Çok uzun bir varchar sütunundaki benzersiz bir dizin nadirdir. Neden ihtiyacınız olduğunu düşünün, çünkü bu bir tasarım sorunu olabilir. Sadece arama için bir dizin istiyorsanız, 191 karaktere uyan bazı 'anahtar kelimeler' alanını düşünün veya metni kısa açıklama ve uzun / tam metne vb. Olarak bölün. Veya tam metin aramasına gerçekten ihtiyacınız varsa, Apache Lucene gibi.
Stijn de Witt

56

sorgunuzdan önce bu sorguyu çalıştır:

SET @@global.innodb_large_prefix = 1;

bu sınırı artıracaktır 3072 bytes.


4
Dünya genelinde innodb_large_prefix olarak değiştirmenin bir dezavantajı var mı? Ve bu DB "küresel" veya tüm DB'LER TAMAMEN KÜRESEL midir?
SciPhi

5
Yalnızca standart olmayan satır formatları kullanılırken geçerlidir. Bkz. Dev.mysql.com/doc/refman/5.5/en/… . Özellikle, DYNAMIC ve COMPRESSED satır biçimlerini kullanan InnoDB tabloları için 767 bayttan (3072 bayta kadar) dizin anahtarı öneklerine izin vermek için bu seçeneği etkinleştirin. Varsayılan satır biçimi etkilenmez.
Chris Lear

5
Bu benim için iyi çalıştı - daha fazla ayrıntı ve bir rehber burada bulunabilir: mechanics.flite.com/blog/2014/07/29/…
cwd

1
bundan sonra mysql sunucusunu yeniden başlatmamız gerekiyor mu?
SimpleGuy

7
Bu cevaptaki önemli eksik ayrıntılar. innodb_file_formatolmalıdır BARRACUDAve tablo düzeyinde ROW_FORMAT=DYNAMICveya kullanmanız gerekir ROW_FORMAT=COMPRESSED. Rehber ile yukarıdaki @ cwd'nin yorumuna bakın.
q0rban

46

Laravel Framework için Çözüm

Gereğince laravel 5.4 * dokümantasyonu. ; Dosyanın bootyöntemi içinde varsayılan dize uzunluğunu app/Providers/AppServiceProvider.phpaşağıdaki gibi ayarlamanız gerekir:

use Illuminate\Support\Facades\Schema;

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

Bu düzeltmenin Laravel 5.4. * Belgeleriyle açıklaması :

Laravel, utf8mb4varsayılan olarak "emojileri" veritabanında saklamak için destek içeren karakter kümesini kullanır . 5.7.7 sürümünden daha eski bir MySQL sürümü veya 10.2.2 sürümünden daha eski bir MariaDB sürümü kullanıyorsanız, MySQL'in kendileri için dizin oluşturması için geçişler tarafından oluşturulan varsayılan dize uzunluğunu el ile yapılandırmanız gerekebilir. Bunu, Schema::defaultStringLengthiçindeki yöntemi çağırarak yapılandırabilirsiniz AppServiceProvider.

Alternatif olarak, innodb_large_prefixveritabanınız için seçeneği etkinleştirebilirsiniz . Bu seçeneğin uygun şekilde etkinleştirilmesine ilişkin talimatlar için veritabanınızın belgelerine bakın.


10
@BojanPetkovic iyi bir Laravel meselesinden geldim ve bu cevap aslında sorunumu çözdü.
mkmnstr

Bu cevap harika. Ama kimse biliyor, neden tam olarak işe yarıyor?
UeliDeSchwert

1
@Bobby Laravel belgeleri "Dizin Uzunlukları ve MySQL / MariaDB" başlığındaki açıklamasını verir laravel.com/docs/5.4/migrations#creating-indexes
Ali Shaukat

1
@Bobby Cevabı güncelledim. Bu düzeltme için laravel belgeleri tarafından verilen açıklamayı ekledim.
Ali Shaukat

39

Hangi karakter kodlamasını kullanıyorsunuz? Bazı karakter kümeleri (UTF-16 ve diğerleri gibi) karakter başına birden fazla bayt kullanır.


8
UTF8 ise, bir karakter 4 bayta kadar kullanabilir, böylece 20 karakter sütunu 20 * 4 + 1bayt ve 500 karakter sütunu 500 * 4 + 2bayt olur
Thanatos

5
Ne için değer, ben sadece aynı sorunu vardı ve utf8_general_ci utf8_unicode_ci geçiş benim için sorunu çözdü. Neden olsa bilmiyorum :(
Andresch Serj

11
Dizini VARCHAR(256)olan bir sütun için UNIQUE, harmanlamayı değiştirmenin @Andresch için yaptığı gibi hiçbir etkisi olmadı. Ancak, uzunluğu 256'dan 255'e düşürmek bunu çözdü. Neden anlamıyorum, karakter başına 767 / max 4 bayt maksimum 191 verir?
Arjan

10
255*3 = 765; 256*3 = 768. Sunucunuz karakter başına 3 bayt varsayıyor gibi görünüyor, @Arjan
Amber

21
@Greg: Haklısınız, ancak bu ayrıntılandırılmalıdır: UTF-8'in kendisi kod noktası başına 1-4 bayt kullanır. MySQL'in "karakter setleri" (gerçekten kodlamalar), UTF-8'in bazılarını kodlayabilen ve kod noktası başına 1-3 bayt kullanan ve BMP dışındaki kod noktalarını kodlayamayan bir karakter kümesine sahiptir . Ayrıca, kod noktası başına 1-4 bayt kullanan ve tüm Unicode kod noktalarını kodlayabilen "utf8mb4" adlı başka bir karakter seti içerir. (utf8mb4 UTF-8, utf8 UTF-8'in garip bir versiyonudur.)
Thanatos

28

Ben varchar (20) sadece 21 bayt gerektirirken varchar (500) sadece 501 bayt gerektirir. Yani toplam bayt sayısı 522, 767'den az. Neden hata mesajını aldım?

UTF8 , dizeyi saklamak için karakter başına 3 bayt gerektirir ; bu nedenle, durumunda 20 + 500 karakter = 20 * 3 + 500 * 3 = 1560 bayt, izin verilen 767 bayttan fazladır .

UTF8 için sınır 767/3 = 255 karakterdir , karakter başına 4 bayt kullanan UTF8mb4 için 767/4 = 191 karakterdir.


Sınırdan daha uzun sütun kullanmanız gerekiyorsa, bu soruna iki çözüm vardır:

  1. Kullanım "ucuz" kodlama (karakterin başına daha az bayt gerektirir bir)
    Benim durumumda, ben sadece kullandıkça, yazının SEO dizesi içeren sütun üzerinde benzersiz bir dizin eklemek için gerekli [A-z0-9\-]kullandığım, SEO için karakterleri latin1_general_cikarakteri başına yalnızca bir bayt kullanan ve böylece sütun 767 bayt uzunluğa sahip olabilir.
  2. Sütununuzdan karma oluşturun ve yalnızca bu konuda benzersiz bir dizin kullanın
    Benim için diğer seçenek SEO'nun karma değerini depolayacak başka bir sütun oluşturmaktı, bu sütun UNIQUESEO değerlerinin benzersiz olmasını sağlamak için anahtar olurdu . Ayrıca, aramayı KEYhızlandırmak için orijinal SEO sütununa dizin ekleyeceğim .

Bu hile yaptı. Varchar (256) yaşadım ve varchar (250) olarak değiştirmek zorunda kaldım.
MaRmAR

25

Neden hata mesajı aldığınızın cevabı burada birçok kullanıcı tarafından zaten cevaplandı. Cevabım nasıl düzeltileceği ve kullanıldığı hakkında.

Bu bağlantıdan bakın .

  1. MySQL istemcisini (veya MariaDB istemcisini) açın. Bir komut satırı aracıdır.
  2. Parolanızı soracak, doğru parolanızı girecektir.
  3. Bu komutu kullanarak veritabanınızı seçin use my_database_name;

Veritabanı değişti

  1. set global innodb_large_prefix=on;

Sorgu tamam, 0 satır etkilendi (0.00 sn)

  1. set global innodb_file_format=Barracuda;

Sorgu tamam, 0 satır etkilendi (0,02 sn)

  1. Kolay yönetim için phpMyAdmin veya bunun gibi bir veritabanında veritabanınıza gidin. > Veritabanı seçin> Tablo yapısını görüntüle > İşlemler sekmesine git . > ROW_FORMAT değerini DYNAMIC olarak değiştirin ve değişiklikleri kaydedin.
  2. Tablonun yapı sekmesine gidin> Benzersiz düğmesini tıklayın.
  3. Bitti. Şimdi hiçbir hata içermemelidir.

Bu düzeltmenin sorunu, db'yi başka bir sunucuya (örneğin localhost'tan gerçek ana bilgisayara) dışa aktarmanız ve bu sunucuda MySQL komut satırını kullanamamanızdır. Orada çalışmasını sağlayamazsınız.


yukarıdaki sorguyu girdikten sonra hala hata yapıyorsanız, "phpmyadmin" e gidin> "harmanlamayı" tercihinize göre ayarlayın (benim için "utf8_general_ci" kullanıyorum)> uygula'yı tıklayın (zaten utf8 olsa bile)
Anthony Kal

Talimatlarınızla çalışan bir araç kullanmıyorum, ancak yine de insanlara sorunu gerçekten düzeltmelerine yardımcı olmaya çalıştığı için oy veriyorum . Soruna neyin sebep olduğuna dair sonsuz açıklamalar var, ancak sorunun nasıl çözüleceğine dair çok az şey var.
Teekin

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

Bu mesajı aldınız çünkü 1 byte sadece latin-1karakter setini kullanırsanız 1 karaktere eşittir . Eğer kullanırsanız utf8anahtar sütunu tanımlarken, her karakterin 3 bayt olarak kabul edilecektir. Eğer kullanırsanız utf8mb4, her karakterin anahtar sütunu tanımlarken 4 bayt olarak kabul edilecektir. Bu nedenle, anahtar alanın izin vermeye çalıştığı bayt sayısını belirlemek için anahtar alanınızın karakter sınırını 1, 3 veya 4 ile çarpmanız gerekir (örneğimde). Uft8mb4 kullanıyorsanız, yerel, InnoDB birincil anahtar alanı için yalnızca 191 karakter tanımlayabilirsiniz. Sadece 767 baytı ihlal etme.


16

uzun sütunların md5 sütununu ekleyebilirsiniz


Bunun, bu sütunlar üzerinde aralık taraması yapmanıza izin vermeyeceğini unutmayın. VARCHAR'lardaki önek uzunlukları, dizinde muhtemelen sahte eşleşmelere (ve bunları ortadan kaldırmak için tarama ve satır aramasına) neden olurken, bu özelliği korumanıza izin verir (kabul edilen cevaba bakın). (Bu aslında manuel olarak uygulanan bir karma dizin, ne yazık ki MysQL InnoDB tabloları ile desteklemiyor.)
Thanatos

Ön ek dizinlerini kullanamadım çünkü H2 ile test amacıyla uyumluluğu sürdürmem gerekiyordu ve bir karma sütun kullanarak iyi çalışıyor. Ben ediyorum şiddetle gibi çarpışmaları oluşturarak kötü niyetli kullanıcılar önlemek için yerine MD5 SHA1 gibi bir çarpışma dirençli işlevini kullanarak öneriyoruz. Sorgularınızdan biri tam sütun değerini değil, yalnızca karma değerini kontrol ederse, bir dizin çarpışmasından veri sızdırabilir.
Küçük Mike

16

İçe aktarma dosyanızda utf8mb4ile değiştirin utf8.

resim açıklamasını buraya girin


Neden tam olarak bunu yapmalı? Ayrıca, bunun herhangi bir dezavantajı varsa (ki sanırım), bunu belirtmelisiniz
Nico Haase

13

Utf8mb4 kullanarak bir VARCHAR (255) alanına UNIQUE dizini eklemeye çalışırken bu sorunla karşılaştık. Sorun burada daha iyi açıklanmış olsa da, bunu nasıl çözdüğümüz ve çözdüğümüze dair pratik öneriler eklemek istedim.

Utf8mb4 kullanıldığında, karakterler 4 bayt olarak sayılırken, utf8 altında 3 bayt olabilir. InnoDB veritabanlarının dizinlerinin yalnızca 767 bayt içerebileceği bir sınırı vardır. Dolayısıyla utf8 kullanırken 255 karakter (767/3 = 255) saklayabilirsiniz, ancak utf8mb4 kullanarak yalnızca 191 karakter (767/4 = 191) depolayabilirsiniz.

VARCHAR(255)Utf8mb4 kullanan alanlar için kesinlikle normal dizinler ekleyebiliyorsunuz , ancak olan şey, dizin boyutunun otomatik olarak 191 karakterde kesildiği - unique_keyburada olduğu gibi :

Dizini gösteren Sequel Pro ekran görüntüsü 191 karakterde kesildi

Bu iyidir, çünkü düzenli indeksler MySQL'in verilerinizde daha hızlı arama yapmasına yardımcı olmak için kullanılır. Tüm alanın dizine eklenmesi gerekmez.

Öyleyse, MySQL neden dizini normal dizinler için otomatik olarak kesiyor, ancak benzersiz dizinler için yapmaya çalışırken açık bir hata atıyor? MySQL'in eklenen veya güncellenen değerin zaten mevcut olup olmadığını anlayabilmesi için, sadece değerin bir kısmını değil, tüm değeri dizine eklemesi gerekir.

Günün sonunda, bir alanda benzersiz bir dizin oluşturmak istiyorsanız, alanın tüm içeriği dizine sığmalıdır. Utf8mb4 için bu, VARCHAR alan uzunluklarınızı 191 veya daha az karaktere düşürmek anlamına gelir. Bu tablo veya alan için utf8mb4'e ihtiyacınız yoksa, onu utf8'e geri bırakabilir ve 255 uzunluk alanınızı koruyabilirsiniz.


11

İşte benim orijinal cevabım:

Ben sadece veritabanı bırakın ve böyle yeniden oluşturun ve hata gitti:

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

Ancak, tüm durumlar için çalışmaz.

Aslında, VARCHAR sütunlarında karakter kümesiyle utf8(veya utf8mb4), belirli bir karakter uzunluğundan daha fazla VARCHAR sütunuyla dizinlerin kullanılması bir sorundur . Durumda utf8mb4, bu uzunluk 191'dir.

MySQL veritabanında uzun dizinlerin nasıl kullanılacağı hakkında daha fazla bilgi için lütfen bu makaledeki Uzun Dizin bölümüne bakın: http://hanoian.com/content/index.php/24-automate-the-converting-a-mysql-database- karakter kümesi-to-utf8mb4


Openmeetings kurulumu için sorun çözüldü (BTW gecemi kurtardın :-)
Ludo

11

5 geçici çözüm:

Sınır 5.7.7'de yükseltildi (MariaDB 10.2.2?). Ve 5.6 (10.1) 'de bir miktar çalışma ile arttırılabilir.

KARAKTER AYARI utf8mb4 kullanmaya çalıştığınız için sınıra ulaşıyorsanız. Ardından, hatayı önlemek için aşağıdakilerden birini yapın (her birinin bir dezavantajı vardır):

  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


10

Bu sorunu şu şekilde çözdüm:

varchar(200) 

ile değiştirildi

varchar(191)

200'den fazla olan tüm varcharlar 191 ile değiştirilir veya metin ayarlanır.


Benim için de işe yaradı. Bir varchar (250) vardı, ama veri asla bu kadar uzun değildi. Varchar (100) olarak değiştirildi. Fikir için teşekkürler :)
Arun Basil Lal

7

Bu konuda biraz arama yaptım nihayet bazı özel değişiklikler aldım

MySQL çalışma tezgahı için 6.3.7 Versiyon Grafiksel ara faz mevcuttur

  1. Workbench'i başlatın ve bağlantıyı seçin.
  2. Yönetim veya Örnek'e gidin ve Seçenekler Dosyası'nı seçin.
  3. Workbench sizden yapılandırma dosyasını okuma ve sonra iki kez Tamam'a basarak izin vermenizi isterse.
  4. Merkez yerde Yönetici seçenekleri dosya penceresi gelir.
  5. InnoDB sekmesine gidin ve Genel bölümünde işaretlenmemişse innodb_large_prefix'i kontrol edin.
  6. innodb_default_row_format seçenek değerini DYNAMIC olarak ayarlayın.

6.3.7'nin altındaki Sürümler için doğrudan seçenekler mevcut değildir, bu nedenle komut istemine gitmeniz gerekir

  1. CMD'yi yönetici olarak başlatın.
  2. Mysql sunucusunun kurulu olduğu yönetmene git Çoğu durumda "C: \ Program Files \ MySQL \ MySQL Server 5.7 \ bin" dizininde komut "cd \" "cd Program Files \ MySQL \ MySQL Server 5.7 \ bin" olur.
  3. Şimdi mysql -u userName -p databasescheema komutunu çalıştırın Şimdi ilgili kullanıcının şifresini istedi. Şifre sağlayın ve mysql istemine girin.
  4. Bazı global ayarları, aşağıdaki komutları birer birer girerek ayarlamak zorundayız. Global innodb_large_prefix = on; set global innodb_file_format = barracuda; set global innodb_file_per_table = true;
  5. Sonunda, gerekli tablonun ROW_FORMAT değerini varsayılan olarak COMPACT olarak değiştirmeliyiz, bunu COMPACT olarak DYNAMIC olarak ayarlamamız gerekir.
  6. aşağıdaki komutu değiştir tabloyu kullan table_name ROW_FORMAT = DYNAMIC;
  7. Bitti

Bunu bulamıyorum: 6. DYNAMIC için innodb_default_row_format seçenek değerini ayarlayın.
Adrian Cid Almaguer

kullanırsam set global innodb_default_row_format = DYNAMIC;şu mesajı görüyorum: ERROR 1193 (HY000): Bilinmeyen sistem değişkeni 'innodb_default_row_format'
Adrian Cid Almaguer

tezgahtan cmd'ye nasıl hata yaptınız? Ben doğrudan seçeneği vardır tezgahtan yaptım.
Abhishek

CMD'den yapıyorum çünkü Workbench'deki seçeneği göremiyorum
Adrian Cid Almaguer

1
Bu varlığın v5.7.9'da tanıtıldığı sorunu görüyorum ve v5.6.33 sürümüne sahibim, teşekkürler
Adrian Cid Almaguer

7

Laravel 5.7 - 6.0 için

İzlenecek adımlar

  1. Adresine gidin App\Providers\AppServiceProvider.php.
  2. Bunu use Illuminate\Support\Facades\Schema;en üstteki sağlayıcıya ekleyin .
  3. Önyükleme işlevinin içinde Bunu ekle Schema::defaultStringLength(191);

hepsi, tadını çıkarın.


Laravel 5.8 için de çalıştı.
Neo

Bu kötü bir çözüm. Sebep: endekslerin sonsuz uzunlukta olması amaçlanmamıştır. Bir şeye benzersiz bir dizin uyguladığınızda, dizinin çoğu zaman sabit olmasını istersiniz. Bu, benzersiz gibi şeyler yapmamanız gerektiği anlamına gelir email, ancak e-postayı hash etmeli ve bunu benzersiz yapmalısınız. Ham dize verilerinin aksine, karma değerler sabit genişliktedir ve dizine eklenip sorunsuz olarak benzersiz hale getirilebilir. Sorunu anlamak yerine, ölçeklendirilmemiş korkunç uygulamalar yayıyorsunuz.
NB

5

harmanlamanızı değiştirin. Neredeyse tümünü destekleyen utf8_general_ci kullanabilirsiniz


"Neredeyse" bunun uzun vadeli bir çözüm olmadığı konusunda oldukça iyi bir ipucu
Nico Haase

4

Sadece değişen utf8mb4için utf8oluşturarak tablolar benim sorun çözüldü zaman. Örneğin: CREATE TABLE ... DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;- CREATE TABLE ... DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;.


4

Bunu düzeltmek için, bu benim için bir cazibe gibi çalışıyor.

ALTER DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;

Sorunumun veritabanı harmanlaması olduğunu da onaylıyorum. Bunun için bir açıklamam yok. MySQL v5.6.32 kullanın ve DB harmanlama utf8mb4_unicode_ci oldu.
mahyard

2

Aşağıda verilen sütuna dayanarak, bu 2 değişken dize sütunu utf8_general_ciharmanlamayı kullanmaktadır ( utf8karakter kümesi ima edilir).

MySQL, utf8karakter kümesi en fazla kullanan 3 bayt her bir karakter için. Bu nedenle, MySQL'in izin verdiği 767 bayttan çok daha büyük olan 500 * 3 = 1500 bayt tahsis edilmesi gerekir. Bu yüzden bu 1071 hatasını alıyorsunuz.

Diğer bir deyişle, karakter kümesini karakter kümesini bayt temsiline göre hesaplamanız gerekir, çünkü her karakter kümesi tek bir bayt temsilidir (tahmin ettiğiniz gibi.) utf8MySQL'de IE karakter başına en fazla 3 bayt kullanır, 767 / 3≈255 karakter ve utf8mb4en fazla 4 baytlık gösterim için 767 / 4≈191 karakter.

Ayrıca MySQL'in

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

1

Bu sorguyu, hangi sütunların maksimum uzunluğu ihlal eden bir dizin olduğunu saptamada yararlı buldum:

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')

1

Lütfen sql_modebunun gibi olup olmadığını kontrol edin

sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

öyleyse, olarak değiştir

sql_mode=NO_ENGINE_SUBSTITUTION

VEYA

my.cnf dosyanızı değiştirerek sunucunuzu yeniden başlatın (aşağıdakileri koyarak)

innodb_large_prefix=on

1

Benim durumumda, linux yeniden yönlendirme çıkış / giriş karakterlerini kullanarak bir veritabanını yedeklerken bu sorunu yaşadım. Bu nedenle, sözdizimini aşağıda açıklandığı gibi değiştiriyorum. PS: linux veya mac terminal kullanarak.

Yedekleme (> yönlendirme olmadan)

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

Geri yükle (<yönlendirme olmadan)

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

"Belirtilen anahtar çok uzun; maksimum anahtar uzunluğu 767 bayt" hatası basitçe kayboldu.


1

Endeks Uzunlukları ve MySQL / MariaDB


Laravel varsayılan olarak utf8mb4 karakter kümesini kullanır ve bu veritabanı veritabanında "emoji" depolamayı destekler . 5.7.7 sürümünden daha eski bir MySQL sürümü veya 10.2.2 sürümünden daha eski bir MariaDB sürümü kullanıyorsanız, MySQL'in kendileri için dizin oluşturması için geçişler tarafından oluşturulan varsayılan dize uzunluğunu el ile yapılandırmanız gerekebilir. AppServiceProvider içinde Schema :: defaultStringLength yöntemini çağırarak bunu yapılandırabilirsiniz :

use Illuminate\Support\Facades\Schema;

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

Alternatif olarak, veritabanınız için innodb_large_prefix seçeneğini etkinleştirebilirsiniz. Bu seçeneğin uygun şekilde etkinleştirilmesine ilişkin talimatlar için veritabanınızın belgelerine bakın.

Blogdan referans: https://www.scratchcode.io/specified-key-too-long-error-in-laravel/

Resmi laravel belgelerinden referans: https://laravel.com/docs/5.7/migrations


0

Şunun gibi bir şey oluşturuyorsanız:

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;

böyle bir şey olmalı

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;

ancak bu sütunun benzersizliğini koddan kontrol etmeniz veya varchar sütununun MD5 veya SHA1'i olarak yeni bir sütun eklemeniz gerekir


3
Sonra benzersiz anahtarınız kayboldu. Bence daha iyi bir yol sadece isim uzunluğunu 191'e düşürmek.
2'de haudoing

1
Neden yerel DB özelliği olup olmadığını programlı olarak benzersizliği kontrol etmek için?
Paweł Tomkiel

0

Önek sınırlamaları nedeniyle bu hata ortaya çıkar. 767 bayt, 5.7 öncesi MySQL sürümlerindeki InnoDB tabloları için belirtilen önek sınırlamasıdır. MyISAM tabloları için 1.000 bayt uzunluğunda. MySQL 5.7 ve sonraki sürümlerde bu sınır 3072 bayta çıkarıldı.

Hata vererek hizmette aşağıdakileri çalıştırmak sorununuzu çözmelidir. Bu MYSQL CLI içinde çalıştırılmalıdır.

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

-1

Şikayetçi dizin alanının CHARSET değerini "latin1" olarak değiştirin,
yani ALTER TABLE tbl CHANGE myfield myfield varchar (600) KARAKTER SETİ latin1 VARSAYILAN BOŞ;
latin1 dört yerine bir karakter için bir bayt alır


5
Ya latin1 olmayan karakterler eklemeye çalışırsa ?
Paweł Tomkiel

4
Bu yapılacak en kötü şey. Bunu asla yapma.
Sebas

1
benim durumumda sadece onaltılık karakterler ile yol adları depolayan bir sütun ... bu yüzden bu birisi için bir çözüm olabilir. gerçekten ne saklamak istediğinize bağlı ...
codewandler

Latin1 kullanmak 2016AD'da bir çözüm olmadığından bunu düşürmek zorunda kaldım. Hala 2007'de latin1'den utf8'e bir veritabanını dönüştürmek zorunda kaldığımız zaman hakkında korkunç kabuslar var. Güzel değil. Hiç.
Bahis Lamed

Bitcoin adreslerini ve işlem kimliklerini sakladığım iki sütunda benzersiz bir dizinde aynı sorunu yaşadım. Bunlar her zaman ASCII karakterleri olacak, bu yüzden bu sütunlarda latin1 kullanacağım. Upvoting.
alexg

-2

innodb_log_file_sizeYakın zamanda değiştirdiyseniz , çalışan önceki değeri geri yüklemeyi deneyin.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.