Mam tabelę z kluczem podstawowym, który jest varchar (255). Pojawiły się przypadki, w których 255 znaków to za mało. Próbowałem zmienić pole na tekst, ale pojawia się następujący błąd:
BLOB/TEXT column 'message_id' used in key specification without a key length
jak mogę to naprawić?
edycja: Powinienem również wskazać, że ta tabela ma złożony klucz podstawowy z wieloma kolumnami.
mysql
sql
mysql-error-1170
GSto
źródło
źródło
UNIQUE
kluczy?Odpowiedzi:
Błąd występuje, ponieważ MySQL może indeksować tylko pierwsze N znaków BLOB lub
TEXT
kolumny. Błąd głównie tak się dzieje, gdy nie jest typ pola / kolumnyTEXT
lub BLOB lub te należą doTEXT
lubBLOB
typy, takie jakTINYBLOB
,MEDIUMBLOB
,LONGBLOB
,TINYTEXT
,MEDIUMTEXT
, iLONGTEXT
że starają się klucz podstawowy lub indeks. Z pełnąBLOB
lubTEXT
bez wartości długości MySQL nie jest w stanie zagwarantować unikatowości kolumny, ponieważ ma ona zmienny i dynamiczny rozmiar. Tak więc, gdy używaszBLOB
lubTEXT
piszemy jako indeks, należy podać wartość N, aby MySQL mógł określić długość klucza. Jednak MySQL nie obsługuje ograniczenia długości klucza dlaTEXT
lubBLOB
.TEXT(88)
po prostu nie zadziała.Błąd pojawi się również, gdy spróbujesz przekonwertować kolumnę tabeli z
non-TEXT
inon-BLOB
wpisać takie jakVARCHAR
iENUM
naTEXT
lubBLOB
wpisać, przy czym kolumna została już zdefiniowana jako unikalne ograniczenia lub indeks. Polecenie Alter Table SQL zakończy się niepowodzeniem.Rozwiązaniem problemu jest usunięcie kolumny
TEXT
lubBLOB
z indeksu lub ograniczenia unikalnego lub ustawienie innego pola jako klucza podstawowego. Jeśli nie możesz tego zrobić i chcesz nałożyć limit na kolumnęTEXT
lubBLOB
, spróbuj użyćVARCHAR
type i umieść na niej limit długości. DomyślnieVARCHAR
jest ograniczony do maksymalnie 255 znaków, a jego limit musi być określony pośrednio w nawiasie zaraz po jego deklaracji, tzn.VARCHAR(200)
Ograniczy go do 200 znaków.Czasami, nawet jeśli nie używasz
TEXT
lub nie używaszBLOB
pokrewnego typu w tabeli, może również pojawić się błąd 1170. Dzieje się tak w sytuacji, gdyVARCHAR
kolumna jest określona jako klucz podstawowy, ale niepoprawnie ustawiono długość lub rozmiar znaków.VARCHAR
Można akceptuje tylko do 256 znaków, więc coś takiego jakVARCHAR(512)
zmusi MySQL do auto-przekonwertowaćVARCHAR(512)
naSMALLTEXT
typ danych, który następnie nie powiedzie się z powodu błędu 1170 o długości klucza, jeśli kolumna jest używana jako klucza podstawowego lub unikalnego lub nie-unikalnego indeksu. Aby rozwiązać ten problem, określ wartośćVARCHAR
pola mniejszą niż 256 .Odniesienie: MySQL Error 1170 (42000): Kolumna BLOB / TEXT używana w specyfikacji klucza bez długości klucza
źródło
Należy zdefiniować, która część wiodąca
TEXT
kolumny ma być indeksowana.InnoDB
ma ograniczenie liczby768
bajtów na klucz indeksu i nie będzie można utworzyć indeksu dłużej.To zadziała dobrze:
Pamiętaj, że maksymalna wartość rozmiaru klucza zależy od zestawu znaków kolumny. Są to
767
znaki jak dla zestawu znaków jednobajtowychLATIN1
i tylko255
dlaUTF8
(MySQL
tylko zastosowaniaBMP
wymagające co najwyżej3
bajtów na znak)Jeśli potrzebujesz, aby cała kolumna była
PRIMARY KEY
obliczeniemSHA1
lubMD5
skrótem i użyj jej jakoPRIMARY KEY
.źródło
REDUNDANT
lubCOMPACT
wiersza. Na przykład możesz przekroczyć ten limit z indeksem prefiksu kolumny dłuższym niż 255 znaków w kolumnieTEXT
lubVARCHAR
, zakładając, że zestaw znaków utf8mb3 i maksymalnie 3 bajty na każdy znak.REDUNDANT
iCOMPACT
były to jedyne formaty dostępne w momencie udzielenia tej odpowiedzi.Możesz określić długość klucza we wniosku o zmianę tabeli, na przykład:
źródło
MySQL zabrania ono indeksowanie pełnej wartości
BLOB
,TEXT
a długiVARCHAR
kolumny, ponieważ dane w nich zawarte mogą być ogromne, a pośrednio indeksu DB będzie duża, co oznacza brak korzyści z indeksu.MySQL wymaga zdefiniowania pierwszych N znaków do indeksowania, a sztuczką jest wybranie liczby N, która jest wystarczająco długa, aby zapewnić dobrą selektywność, ale wystarczająco krótką, aby zaoszczędzić miejsce. Prefiks powinien być wystarczająco długi, aby indeks był tak samo przydatny, jak w przypadku indeksowania całej kolumny.
Zanim przejdziemy dalej, zdefiniujmy kilka ważnych terminów. Selektywność indeksu to stosunek całkowitych odrębnych indeksowanych wartości i całkowitej liczby wierszy . Oto jeden przykład tabeli testowej:
Jeśli indeksujemy tylko pierwszy znak (N = 1), wówczas tabela indeksów będzie wyglądać następująco:
W tym przypadku selektywność indeksu jest równa IS = 1/3 = 0,33.
Zobaczmy teraz, co się stanie, jeśli zwiększymy liczbę indeksowanych znaków do dwóch (N = 2).
W tym scenariuszu IS = 2/3 = 0,66, co oznacza, że zwiększyliśmy selektywność indeksu, ale zwiększyliśmy również rozmiar indeksu. Sztuczka polega na znalezieniu minimalnej liczby N, która doprowadzi do maksymalnej selektywności indeksu .
Istnieją dwa podejścia do wykonywania obliczeń dla tabeli bazy danych. Zrobię demonstrację w Internecie tym zrzutu bazy danych .
Powiedzmy, że chcemy dodać do indeksu kolumnę nazwisko w pracownikach tabeli i chcemy zdefiniować najmniejszą liczbę N która zapewni najlepszą selektywność indeksu.
Najpierw określmy najczęstsze nazwiska:
Jak widać, nazwisko Baba jest najczęstsze. Teraz znajdziemy najczęściej występujące prefiksy nazwisk , zaczynając od pięcioliterowych prefiksów.
Występuje znacznie więcej wystąpień każdego prefiksu, co oznacza, że musimy zwiększać liczbę N, aż wartości będą prawie takie same jak w poprzednim przykładzie.
Oto wyniki dla N = 9
Oto wyniki dla N = 10.
To bardzo dobre wyniki. Oznacza to, że możemy wykonać indeks na kolumnie
last_name
z indeksowaniem tylko pierwszych 10 znaków. W definicji tabeli kolumnalast_name
jest zdefiniowana jakoVARCHAR(16)
, a to oznacza, że zapisaliśmy 6 bajtów (lub więcej, jeśli w nazwisku występuje znak UTF8) na pozycję. W tej tabeli znajduje się 1637 różnych wartości pomnożonych przez 6 bajtów, czyli około 9 KB, i wyobraź sobie, jak ta liczba by wzrosła, gdyby nasza tabela zawierała milion wierszy.Możesz przeczytać inne sposoby obliczania liczby N w moim poście Prefiksy indeksów w MySQL .
źródło
Wystąpił ten błąd podczas dodawania indeksu do tabeli z kolumnami typu tekstowego. Musisz zadeklarować rozmiar, którego chcesz użyć dla każdego typu tekstu.
Wprowadź wielkość rozmiaru w nawiasie ()
Jeśli używanych jest zbyt wiele bajtów, możesz zadeklarować rozmiar w nawiasach dla varchar, aby zmniejszyć ilość używaną do indeksowania. Dzieje się tak nawet wtedy, gdy zadeklarowałeś rozmiar typu już takiego jak varchar (1000). Nie musisz tworzyć nowego stołu, jak powiedzieli inni.
Dodawanie indeksu
Dodanie unikalnego indeksu
źródło
UWAGA : 767 to liczba znaków do której MySQL będzie indeksował kolumny podczas zajmowania się indeksami obiektów blob / text
Ref: http://dev.mysql.com/doc/refman/5.7/en/innodb-restrictions.html
źródło
Innym doskonałym sposobem radzenia sobie z tym jest utworzenie pola TEXT bez wyjątkowego ograniczenia i dodanie pola VARCHAR rodzeństwa, które jest unikalne i zawiera skrót (MD5, SHA1 itp.) Pola TEXT. Oblicz i przechowuj podsumowanie w całym polu TEXT, gdy wstawiasz lub aktualizujesz pole TEXT, wtedy masz ograniczenie unikatowości w całym polu TEXT (a nie w części wiodącej), które można szybko przeszukać.
źródło
Nie używaj długich wartości jako klucza podstawowego. To zniszczy twoje osiągi. Zobacz instrukcję mysql, rozdział 13.6.13 „InnoDB Performance Tuning and Rozwiązywanie problemów”.
Zamiast tego należy mieć zastępczy klucz int jako podstawowy (z auto_increment), a swój klucz loong jako dodatkowy UNIQUE.
źródło
Dodaj kolejną kolumnę varChar (255) (domyślnie jako pusty ciąg znaków nie jest pusty), aby wstrzymać przepełnienie, gdy 255 znaków nie wystarczy, i zmień tę PK, aby użyć obu kolumn. Nie wydaje się to jednak dobrze zaprojektowanym schematem bazy danych i zaleciłbym, aby modelarz danych spojrzał na to, co masz, z myślą o przefaktoryzowaniu go w celu uzyskania większej normalizacji.
źródło
Rozwiązaniem tego problemu jest to, że w
CREATE TABLE
instrukcji można dodać ograniczenieUNIQUE ( problemtextfield(300) )
po utworzeniu definicji kolumny, aby na przykład określićkey
długość300
znaków dlaTEXT
pola. Wtedy pierwsze300
znaki zproblemtextfield
TEXT
pola będą musiały być unikalne, a wszelkie późniejsze różnice zostaną zignorowane.źródło
Ponadto, jeśli chcesz użyć indeksu w tym polu, powinieneś użyć silnika pamięci MyISAM i typu indeksu FULLTEXT.
źródło
Jak dotąd nikt o tym nie wspominał ... z utf8mb4, który jest 4-bajtowy i może również przechowywać emotikony (nigdy nie powinniśmy więcej używać 3-bajtowego utf8) i możemy uniknąć błędów, tak jak
Incorrect string value: \xF0\x9F\x98\...
nie powinniśmy używać typowego VARCHAR (255), a raczej VARCHAR ( 191) ponieważ w przypadku, gdy utf8mb4 i VARCHAR (255) ta sama część danych jest przechowywana poza stroną i nie możesz utworzyć indeksu dla kolumny VARCHAR (255), ale dla VARCHAR (191) możesz to zrobić. Jest tak, ponieważ maksymalny rozmiar indeksowanej kolumny to 767 bajtów dla ROW_FORMAT = COMPACT lub ROW_FORMAT = REDUNDANT.W przypadku nowszych formatów wierszy ROW_FORMAT = DYNAMIC lub ROW_FORMAT = COMPRESSED (co wymaga nowszego formatu pliku innodb_file_format = Barracuda nie jest starszą antylopą) maksymalny rozmiar indeksowanej kolumny to 3072. Jest dostępny od MySQL> = 5.6.3, gdy innodb_large_prefix = 1 (domyślnie wyłączone MySQL <= 5.7.6 i domyślnie włączony dla MySQL> = 5.7.7). Więc w tym przypadku możemy użyć VARCHAR (768) dla utf8mb4 (lub VARCHAR (1024) dla starego utf8) dla kolumny indeksowanej. Opcja innodb_large_prefix jest przestarzała od 5.7.7, ponieważ jej zachowanie jest wbudowane w MySQL 8 (w tej wersji opcja jest usunięta).
źródło
Musisz zmienić typ kolumny na
varchar
lubinteger
do indeksowania.źródło
Przejdź do mysql
edit table
-> zmień typ kolumny navarchar(45)
.źródło
Użyj w ten sposób
źródło