Czy deklarowanie VARCHAR
rozmiaru ma sens dla wydajności? Czy jest jakaś różnica (w prędkości) między VARCHAR(50)
i VARCHAR(255)
? Czy też definiowanie długości jest ograniczeniem logicznym / projektowym?
mysql
database-design
Sonique
źródło
źródło
Odpowiedzi:
Jest to bardzo częste „pytanie egzaminacyjne / rozmowa kwalifikacyjna”. Odpowiem tak dobrze, jak potrafię:
W standardowych formatach wierszy dla InnoDB i MyISAM (dynamiczny / kompaktowy) a
VARCHAR(50)
i aVARCHAR(255)
będą przechowywać tekst łańcucha w ten sam sposób - 1 bajt dla długości i rzeczywisty łańcuch z 1 do 4 bajtów na znak (w zależności od kodowania i rzeczywisty zapisany znak).W rzeczywistości, jeśli dobrze pamiętam, przypominam sobie kogoś, kto modyfikuje słownik danych za pomocą edytora szesnastkowego, aby zmienić coś w rodzaju
VARCHAR(50)
na aVARCHAR(100)
, więc można to zrobić dynamicznie (zwykle wymaga to rekonstrukcji tabeli). I było to możliwe, ponieważ zmiana nie wpłynęła na faktyczne dane.Nie jest tak w przypadku
VARCHAR(256)
, ponieważ zawsze wymagane są 2 bajty (przynajmniej) dla długości.Tak, to oznacza, że zawsze powinniśmy zrobić
VARCHAR(255)
, nie powinniśmy? Nie. Jest kilka powodów.Podczas gdy InnoDB może przechowywać varchar w sposób dynamiczny, nie dotyczy to innych silników. MyISAM ma stały format rozmiaru wiersza, a tabele MEMORY mają zawsze stały rozmiar. Czy powinniśmy dbać o te inne silniki? Tak, powinniśmy, ponieważ nawet jeśli nie używamy ich bezpośrednio, tabele MEMORY są bardzo często używane do wyników pośrednich (tabele tymczasowe w pamięci) , a ponieważ wyniki nie są wcześniej znane, tabelę należy utworzyć z maksymalnym rozmiarem możliwe -
VARCHAR(255)
jeśli taki jest nasz typ. Jeśli możesz pomyśleć o zmarnowanym miejscu, jeśli używamy'utf8' charset
kodowania MySQL , MEMORY zarezerwuje 2 bajty na długość + 3 * 255 bajtów na wiersz(dla wartości, które mogą zająć tylko kilka bajtów w InnoDB). To prawie 1 GB na 1 milion tabeli - tylko dla VARCHAR. Powoduje to nie tylko niepotrzebne obciążenie pamięci, ale może również powodować działania na dysku, co może spowalniać tysiące razy. Wszystko to z powodu złego wyboru określonego typu danych (niezależnie od zawartości).Ma to również pewne konsekwencje dla InnoDB. Rozmiar indeksu jest ograniczony do 3072 bajtów i indeksów jednokolumnowych do 767 bajtów *. Jest więc bardzo prawdopodobne, że nie będziesz w stanie indeksować w pełni
VARCHAR(255)
pola (zakładając, że używasz utf8 lub innego kodowania o zmiennej długości).Dodatkowo maksymalny rozmiar wiersza dla InnoDB wynosi pół strony (około 8000 bajtów), a pola o zmiennej długości, takie jak BLOB lub varchar, mogą być przechowywane poza stroną, jeśli nie mieszczą się na połowie strony . Ma to pewne konsekwencje w wydajności (czasem dobre, czasem złe, w zależności od użycia), których nie można zignorować. Spowodowało to pewną dziwność między formatami COMPACT i DYNAMIC. Zobacz na przykład: błąd 1118: zbyt duży rozmiar wiersza. utf8 innodb
Last but not least, jak przypomniała mi @ypercube, może być wymagany więcej niż 1 bajt dla długości, nawet jeśli używasz
VARCHAR(255)
, ponieważ definicja jest w postaci znaków, podczas gdy długość przechowuje bajty. Na przykładREPEAT('ñ', 255)
ma więcej niż 2 ^ 255 bajtów w utf8, więc do przechowywania jego długości potrzebowałby więcej niż 1 bajt:Tak więc ogólna rada polega na użyciu możliwie najmniejszego typu , ponieważ w przeciwnym razie może potencjalnie powodować problemy z wydajnością lub zarządzaniem. A
VARCHAR(100)
jest lepsze niżVARCHAR(255)
(choćVARCHAR(20)
byłoby lepsze), nawet jeśli nie znasz dokładnej długości. Staraj się być konserwatywny, ponieważ jeśli tabela nie jest zbyt duża, zawsze możesz później zmienić definicję.Aktualizacja: Ze względu na ogromną popularność ciągów o zmiennej długości, na przykład za pomocą emoji, Oracle dąży do poprawy wydajności w tych przypadkach. W najnowszych wersjach MySQL (5.6, 5.7) InnoDB został ustawiony jako domyślny silnik zarówno wewnętrznych, jak i jawnych tabel tymczasowych, co oznacza, że pola o zmiennej długości są teraz pierwszorzędnymi obywatelami. Oznacza to, że może istnieć mniej powodów, aby mieć bardzo ograniczone długości znaków (ale nadal istnieją).
(*) Druga aktualizacja : duży_prefiks_indeks jest teraz domyślnie włączony w najnowszych wersjach MySQL (8.0), ale nadal tak jest w przypadku starszych wersji lub jeśli używasz opóźnionych formatów plików / wierszy (innych niż dynamiczne lub skompresowane), ale teraz domyślnie indeksy jednokolumnowe mogą mieć maksymalnie 3072 bajty.
źródło
Zapomnij o włączonym 1- i 2-bajtowym prefiksie
VARCHARs
.Pytanie o 255 zostało zadane i udzielono odpowiedzi wiele razy.
VARCHARs
może prowadzić do awariiCREATE TABLE
.MEMORY
tabele, zVARCHARs
przekształconymi wVARCHAR
. Oznacza to na przykład, żeVARCHAR(255) CHARACTER SET utf8mb4
chce mieć stałą długość 1020 bajtów. (To się nie powiedzie i zdegeneruje się przy użyciu MyISAM.)Konkluzja: Nie używaj na ślepo 255 (lub 256); rób to, co ma sens dla schematu.
źródło