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


103

Bu başlığa sahip soruların daha önce yanıtlandığını biliyorum, ancak lütfen okumaya devam edin. Göndermeden önce bu hatayla ilgili diğer tüm soruları / cevapları iyice okudum.

Aşağıdaki sorgu için yukarıdaki hatayı alıyorum:

CREATE TABLE IF NOT EXISTS `pds_core_menu_items` (
  `menu_id` varchar(32) NOT NULL,
  `parent_menu_id` int(32) unsigned DEFAULT NULL,
  `menu_name` varchar(255) DEFAULT NULL,
  `menu_link` varchar(255) DEFAULT NULL,
  `plugin` varchar(255) DEFAULT NULL,
  `menu_type` int(1) DEFAULT NULL,
  `extend` varchar(255) DEFAULT NULL,
  `new_window` int(1) DEFAULT NULL,
  `rank` int(100) DEFAULT NULL,
  `hide` int(1) DEFAULT NULL,
  `template_id` int(32) unsigned DEFAULT NULL,
  `alias` varchar(255) DEFAULT NULL,
  `layout` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`menu_id`),
  KEY `index` (`parent_menu_id`,`menu_link`,`plugin`,`alias`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Bunun neden ve nasıl düzeltileceği hakkında bir fikri olan var mı? İşin püf noktası - bu aynı sorgu yerel makinemde mükemmel çalışıyor ve önceki ana makinemde de çalışıyor. Btw.it olgun bir projeden - phpdevshell - bu yüzden bu adamların ne yaptıklarını bildiklerini tahmin ediyorum, ama siz asla bilemezsiniz.

Herhangi bir ipucu takdir edildi.

PhpMyAdmin kullanıyorum.

Yanıtlar:


172

@ Devart'ın dediği gibi, dizininizin toplam uzunluğu çok uzun.

Kısa cevap, bu kadar uzun VARCHAR sütunlarını zaten indekslememeniz gerektiğidir, çünkü indeks çok büyük ve verimsiz olacaktır.

En iyi uygulama, önek dizinlerini kullanmaktır, böylece verilerin yalnızca sol bir alt dizesini dizine eklersiniz. Verilerinizin çoğu zaten 255 karakterden çok daha kısa olacaktır.

Dizini tanımlarken, sütun başına bir önek uzunluğu tanımlayabilirsiniz. Örneğin:

...
KEY `index` (`parent_menu_id`,`menu_link`(50),`plugin`(50),`alias`(50))
...

Ancak belirli bir sütun için en iyi önek uzunluğu nedir? İşte öğrenmek için bir yöntem:

SELECT
 ROUND(SUM(LENGTH(`menu_link`)<10)*100/COUNT(`menu_link`),2) AS pct_length_10,
 ROUND(SUM(LENGTH(`menu_link`)<20)*100/COUNT(`menu_link`),2) AS pct_length_20,
 ROUND(SUM(LENGTH(`menu_link`)<50)*100/COUNT(`menu_link`),2) AS pct_length_50,
 ROUND(SUM(LENGTH(`menu_link`)<100)*100/COUNT(`menu_link`),2) AS pct_length_100
FROM `pds_core_menu_items`;

menu_linkSütunda belirli bir dize uzunluğundan daha fazla olmayan satırların oranını size söyler . Bunun gibi çıktı görebilirsiniz:

+---------------+---------------+---------------+----------------+
| pct_length_10 | pct_length_20 | pct_length_50 | pct_length_100 |
+---------------+---------------+---------------+----------------+
|         21.78 |         80.20 |        100.00 |         100.00 |
+---------------+---------------+---------------+----------------+

Bu size dizelerinizin% 80'inin 20 karakterden az olduğunu ve tüm dizelerinizin 50 karakterden az olduğunu söyler. Bu nedenle, 50 ön ek uzunluğundan fazlasını indekslemeye gerek yoktur ve kesinlikle 255 karakterlik tam uzunlukta indekslemeye gerek yoktur.

Not: INT(1)ve INT(32)veri türleri MySQL hakkında başka bir yanlış anlaşılmaya işaret ediyor. Sayısal bağımsız değişkenin depolamayla veya sütun için izin verilen değer aralığıyla ilgili hiçbir etkisi yoktur. INTher zaman 4 bayttır ve her zaman -2147483648 ile 2147483647 arasındaki değerlere izin verir. Sayısal bağımsız değişken, görüntüleme sırasında değerlerin doldurulmasıyla ilgilidir ve ZEROFILLseçeneği kullanmadığınız sürece hiçbir etkisi yoktur .


17
Ayrıntılı açıklama için çok teşekkürler. Bir sorunu çözmenin yanı sıra, değerli bir şey de öğrendim.
CodeVirtuoso

Dizinin ayarlanması gereken uzunluğu bulmak için gerçekten çok yararlı bir sorgu. Bir dizin için en iyi uzunluğu belirlemek için bunu bazı zamanlar kullanıyorum. Paylaşım için teşekkürler!
Niraj Kumar

1
Kullanışlı sorgunuzda, dizelerin gerçekte ne kadar uzun olduğunu ölçmek için küçük bir hata var: dizelerin hepsinin mevcut olduğunu varsayıyorsunuz; yani, hepsi orada. Bazıları boşsa, hesaplamalarınızı atar ve kısa dizeleri eksik rapor eder. Count (*) yerine count ([field_name]) kullanmak istiyorsunuz.
D Mac

İlk "önek" dizininden fazlasını kullanmaz.
Rick James

28

Bu hata, indeks uzunluğunun index1000 bayttan fazla olduğu anlamına gelir . MySQL ve depolama motorları bu kısıtlamaya sahip olabilir. MySQL 5.5'te benzer bir hata aldım - 'Belirtilen anahtar çok uzundu; Bu komut dosyası çalıştırıldığında maksimum anahtar uzunluğu 3072 bayttır:

CREATE TABLE IF NOT EXISTS test_table1 (
  column1 varchar(500) NOT NULL,
  column2 varchar(500) NOT NULL,
  column3 varchar(500) NOT NULL,
  column4 varchar(500) NOT NULL,
  column5 varchar(500) NOT NULL,
  column6 varchar(500) NOT NULL,
  KEY `index` (column1, column2, column3, column4, column5, column6)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

UTF8 çok baytlıdır ve anahtar uzunluğu bu şekilde hesaplanır - 500 * 3 * 6 = 9000 bayt.

Ancak bir sonraki sorgu işe yarıyor!

CREATE TABLE IF NOT EXISTS test_table1 (
  column1 varchar(500) NOT NULL,
  column2 varchar(500) NOT NULL,
  column3 varchar(500) NOT NULL,
  column4 varchar(500) NOT NULL,
  column5 varchar(500) NOT NULL,
  column6 varchar(500) NOT NULL,
  KEY `index` (column1, column2, column3, column4, column5, column6)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

... CHARSET = latin1 kullandım, bu durumda anahtar uzunluğu 500 * 6 = 3000 bayt.


7
Cevabınız için teşekkürler, bu işe yarıyor, ancak utf8 karakter setinden vazgeçme pahasına. Bu kısıtlama bir şekilde aşılabilir mi (tam sunucu erişimim var), bunun iyi bir nedeni var mı?
CodeVirtuoso

4
Bu berbat bir tavsiye, lütfen karakter setlerinin ne olduğunu ve bunun gelecekte nasıl büyük sorunlara neden olacağını öğrenin. Karma karakter kümesi veritabanı, yalnızca birleştirmeler veya alt seçimler kullanılırken sorunlara neden olmaz, verilerinizi normalleştirilmemiş bir biçime yerleştirir ve daha sonra düzeltilmesi neredeyse imkansız olabilir.
Geoffrey

17

Bu sorunu yaşadım ve aşağıdaki şekilde çözdüm:

Sebep olmak

MyISAM, UTF8 karakter seti ve buradan kontrol edebileceğiniz dizinler ile ilgili MySQL ile ilgili bilinen bir hata var.

çözüm

  • MySQL'in InnoDB depolama motoruyla yapılandırıldığından emin olun.

  • Varsayılan olarak kullanılan depolama motorunu değiştirin, böylece yeni tablolar her zaman uygun şekilde oluşturulacaktır:

    set GLOBAL storage_engine='InnoDb';

  • MySQL 5.6 ve sonrası için aşağıdakileri kullanın:

    SET GLOBAL default_storage_engine = 'InnoDB';

  • Ve son olarak MySQL'e Geçiş bölümünde verilen talimatları izlediğinizden emin olun .

Referans


Çoğu durumda, depolama motorunu 'InnoDB' olarak yapılandırmayı unutuyoruz. Aşağıdaki cevap en basit olanıdır ve muhtemelen buradaki çoğu kullanıcı için sorunu çözecektir. Teşekkürler.
Frederiko Cesar

10

tablo oluşturmadan veya değiştirmeden önce bu sorguyu çalıştırın.

SET @@global.innodb_large_prefix = 1;

bu, maksimum anahtar uzunluğunu 3072 bayta ayarlar


3

Bu dizin boyutu sınırı, MySQL'in 64 bit yapılarında daha büyük görünüyor.

Dev veritabanımızı boşaltmaya ve yerel bir VMWare sanal aygıtına yüklemeye çalışırken bu sınırlamaya ulaşıyordum. Sonunda uzak dev sunucusunun 64 bit olduğunu fark ettim ve 32 bitlik bir sanal yaratmıştım. Az önce 64 bitlik bir sanal yarattım ve veritabanını yerel olarak yükleyebildim.


2

Sadece orijinal veritabanındaki "uzunluk" değerini yapısını değiştirerek ve ardından bunu sunucuya aktararak toplam "1000" değerine değiştirerek bu hatayı atlattım. :)


0

Aynı sorunla karşılaşıyordum, çözmek için aşağıdaki sorguyu kullandım.

DB oluştururken utf-8 kodlamasını kullanabilirsiniz

Örneğin. create database my_db character set utf8 collate utf8mb4;

DÜZENLEME: (Yorumlardan gelen önerileri dikkate alarak) utf8_bin utf8mb4 olarak değiştirildi


2
Bu beni doğru yönü gösterdi. Benim için harmanlamamı şu şekilde değiştirmek zorunda kaldım: utf8_general_ci
Ian Newland

2
Bu doğru yön DEĞİL, bunu yapmayın! MySQL utf8, DEĞİLDİR utf8, asla gerçekleşmemesi gereken gizli bir özel biçimdir. utf8mb4doğrudur utf8ve uygun utf8destek için önerilen varsayılan değerdir .
Geoffrey

utf8mb4utf8
mysql'de

Bu sadece bir örnekti - yine de cevabı güncelledim.
Sudhir Dhumal
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.