Czy istnieją wady używania ogólnego varchar (255) dla wszystkich pól tekstowych?

100

Mam contactstabelę, która zawiera pola, takie jak postcode, first name, last name, town, country, phone numberitp, z których wszystkie są zdefiniowane jako VARCHAR(255)choć żaden z tych pól będzie kiedykolwiek zbliży się do posiadania 255 znaków. (Jeśli się zastanawiasz, dzieje się tak, ponieważ migracje Ruby on Rails VARCHAR(255)domyślnie mapują pola typu String na i nigdy nie zadałem sobie trudu, aby go przesłonić).

Ponieważ VARCHAR przechowuje tylko liczbę rzeczywistych znaków pola (wraz z długością pola), czy jest jakaś wyraźna przewaga (wydajność lub inna) w używaniu, powiedzmy, VARCHAR(16)nad VARCHAR(255)?

Ponadto większość z tych pól ma indeksy. Czy większy rozmiar VARCHAR w polu w ogóle wpływa na rozmiar lub wydajność indeksu?

FYI Używam MySQL 5.

Olly
źródło
2
@ceejayoz, stwierdzając, że zaakceptowana odpowiedź jest niepoprawna, bez wyjaśnienia, dlaczego tak naprawdę nie pomaga. Co czyni go jeszcze gorsze jest to, że akceptowaną odpowiedź może się zmieniać w czasie, a Twój komentarz będzie mylić ludzi do myślenia nowy odpowiedź akceptowana jest nieprawidłowy.
Gili,
1
@Gili Usunąłem mój komentarz, ponieważ OP najwyraźniej zmienił swoją akceptację. Słuszna uwaga, w przyszłości wskażę, o której odpowiedzi mówię i dlaczego.
ceejayoz
Kilka innych odpowiedzi na to zduplikowane pytanie, stackoverflow.com/questions/1262174/ ...
James McMahon

Odpowiedzi:

129

W magazynie VARCHAR(255)jest wystarczająco sprytny, aby przechowywać tylko potrzebną długość w danym wierszu, w przeciwieństwie do tego, CHAR(255)który zawsze przechowuje 255 znaków.

Ale ponieważ oznaczyłeś to pytanie za pomocą MySQL, wspomnę o wskazówce specyficznej dla MySQL: gdy wiersze są kopiowane z warstwy silnika pamięci do warstwy SQL, VARCHARpola są konwertowane, CHARaby uzyskać przewagę pracy z wierszami o stałej szerokości. Zatem ciągi w pamięci są dopełniane do maksymalnej długości zadeklarowanej VARCHARkolumny.

Gdy zapytanie niejawnie generuje tabelę tymczasową, na przykład podczas sortowania lub GROUP BY, może to zająć dużo pamięci. Jeśli używasz wielu VARCHAR(255)pól na dane, które nie muszą być tak długie, może to spowodować, że tabela tymczasowa będzie bardzo duża.

Możesz również chcieć wiedzieć, że to zachowanie "wypełnienia" oznacza, że ​​ciąg zadeklarowany za pomocą zestawu znaków utf8 wypełnia do trzech bajtów na znak, nawet dla łańcuchów, które przechowujesz z zawartością jednobajtową (np. Znaki ascii lub latin1). Podobnie zestaw znaków utf8mb4 powoduje, że ciąg w pamięci jest wypełniony do czterech bajtów na znak.

Tak więc VARCHAR(255)w utf8 przechowywanie krótkiego ciągu, takiego jak „Brak opinii”, zajmuje 11 bajtów na dysku (dziesięć znaków z małymi znakami plus jeden bajt na długość), ale zajmuje 765 bajtów w pamięci, a więc w tabelach tymczasowych lub posortowanych wynikach.

Pomogłem użytkownikom MySQL, którzy często nieświadomie tworzyli tabele tymczasowe o pojemności 1,5 GB i zapełniali przestrzeń dyskową. Mieli wiele VARCHAR(255)kolumn, które w praktyce przechowywały bardzo krótkie ciągi.

Najlepiej zdefiniować kolumnę na podstawie typu danych, które zamierzasz przechowywać. Ma zalety wymuszania ograniczeń związanych z aplikacjami, jak wspominali inni ludzie. Ale ma fizyczne zalety, aby uniknąć marnowania pamięci, które opisałem powyżej.

Trudno oczywiście wiedzieć, jaki jest najdłuższy adres pocztowy, dlatego wiele osób wybiera długi VARCHAR, z pewnością dłuższy niż jakikolwiek adres. A 255 jest zwyczajowe, ponieważ jest to maksymalna długość a, VARCHARdla której długość można zakodować jednym bajtem. Była to również maksymalna VARCHARdługość w MySQL starsza niż 5.0.

Bill Karwin
źródło
6
Zawsze myślałem, że 255został użyty tak, aby długość ciągu mogła zmieścić się w jednym bajcie
BlueRaja - Danny Pflughoeft
3
@BlueRaja: Prawdopodobnie było to prawdą w przypadku baz danych, których wewnętrzna struktura pliku zakodowała długość ciągu w jednym bajcie lub jeśli zakodowały krótkie ciągi w jednym bajcie. Ale nie jest to już prawdą w przypadku większości baz danych.
Bill Karwin,
7
@BlueRaja: InnoDB nie przechowuje długości następującego varchar, przechowuje serię przesunięć pól dla wszystkich pól w wierszu. Te przesunięcia pól mogą wynosić 1 bajt, jeśli łączny rozmiar wiersza jest mniejszy niż 127 bajtów lub 2 bajty. Zobacz forge.mysql.com/wiki/MySQL_Internals_InnoDB
Bill Karwin,
6
@BlueRaja: MyISAM (dla tych, którzy nadal go używają) przechowuje długości varchar, które mogą być przechowywane w 1 lub 2 bajtach. Jednak: „Wysyłając klucz do programu obsługi dla index_read () lub records_in_range, zawsze używamy 2-bajtowej długości VARCHAR, aby uprościć sprawę.” Zobacz forge.mysql.com/wiki/MySQL_Internals_MyISAM
Bill Karwin,
1
jedno pytanie - sortowanie i grupowanie według dowolnego pola lub samego pola varchar?
Rohit Banga
24

Oprócz kwestii związanych z rozmiarem i wydajnością związanych z ustawieniem rozmiaru varchar (i być może ważniejszym, ponieważ przechowywanie i przetwarzanie tańszą co sekundę), wadą używania varchar (255) „tylko dlatego” jest zmniejszona integralność danych .

Zdefiniowanie maksymalnych limitów dla łańcuchów jest dobrą rzeczą do zrobienia, aby zapobiec wprowadzaniu dłuższych niż oczekiwane ciągów do RDBMS i powodowaniu przepełnień buforu lub wyjątków / błędów później podczas pobierania i analizowania wartości z bazy danych, które są dłuższe (więcej bajtów) niż oczekiwano.

Na przykład, jeśli masz pole, które akceptuje dwuznakowe ciągi znaków dla skrótów krajów, nie masz żadnego powodu, aby oczekiwać, że Twoi użytkownicy (w tym kontekście programiści) będą wprowadzać pełne nazwy krajów. Ponieważ nie chcesz, aby wpisywali „Antigua i Barbuda” (AG) lub „Wyspy Heard i McDonalda” (HM), nie zezwalasz na to w warstwie bazy danych. Jest również prawdopodobne, że niektórzy programiści nie przygotowali jeszcze RTFM dokumentacji projektowej ( która z pewnością istnieje ), aby wiedzieć, aby tego nie robić.

Ustaw pole tak, aby akceptowało dwa znaki i pozwól systemowi RDBMS sobie z nim poradzić (z wdziękiem przez obcięcie lub niezręcznie przez odrzucenie ich kodu SQL z błędem).

Przykłady prawdziwych danych, które nie mają powodu, aby przekraczać określoną długość:

  • Kanadyjskie kody pocztowe mają format A1A1A1 i zawsze mają długość 6 znaków, nawet dla Świętego Mikołaja (6 znaków wyklucza spację, którą można określić dla czytelności).
  • adresy e-mail - do 64 bajtów przed znakiem @, do 255 bajtów po. Nigdy więcej, abyś nie przerwał Internetu.
  • Numery telefonów w Ameryce Północnej nigdy nie są dłuższe niż 10 cyfr (z wyłączeniem kodu kraju).
  • Komputery z systemem Windows (najnowsze wersje) nie mogą mieć nazw komputerów dłuższych niż 63 bajty , chociaż nie zaleca się ich używania więcej niż 15 i spowoduje uszkodzenie farmy serwerów Windows NT.
  • Skróty stanów składają się z 2 znaków (jak w przykładowych kodach krajów powyżej)
  • Numery monitorowania UPS mają 18, 12, 11 lub 9 znaków. Liczby 18-znakowe zaczynają się od „1Z”, a liczby 11-znakowe zaczynają się od „T”, co sprawia, że ​​zastanawiasz się, jak dostarczają wszystkie te pakiety, jeśli nie znają różnicy między literami a cyframi.

I tak dalej...

Poświęć trochę czasu na przemyślenie swoich danych i ich ograniczeń. Jeśli jesteś architektem, programistą lub programistą, w końcu to twoja praca .

Używając varchar (n) zamiast varchar (255), eliminujesz problem polegający na tym, że użytkownicy (użytkownicy końcowi, programiści, inne programy) wprowadzają nieoczekiwanie długie dane , które wrócą później, by prześladować twój kod.

I nie powiedziałem, że nie należy również implementować tego ograniczenia w kodzie logiki biznesowej używanej przez aplikację.

shufler
źródło
5
Kanadyjskie kody pocztowe mają w rzeczywistości 7 cyfr, odstęp w środku jest ważny i powinien być umieszczony na etykietach wysyłkowych. Numery telefonów w Ameryce Północnej mogą mieć więcej niż 10 cyfr, jeśli istnieje rozszerzenie. Jeśli nie masz możliwości zapisania numerów wewnętrznych, 10 cyfr jest w porządku, ale prawdopodobnie będziesz tego żałować.
Kibbee,
3
Z pewnością istnieją argumenty za ograniczeniem integralności danych. Chociaż nadal łatwo jest być zbyt restrykcyjnym. Nakładaj ograniczenia na dane, które kontrolujesz, i rozsądne ograniczenia dotyczące wymagań dotyczących danych, nad którymi nie masz kontroli. Twój numer telefonu i ograniczenia dotyczące e-maili są rozsądne (zakładając, że nigdy nie umiędzynarodowisz). Twój wymóg, który mówi, że skracanie dwuznakowego kodu kraju jest „wdzięczną” rzeczą, jest szalony. Wiesz, że wystąpił błąd, nie skracaj i nie akceptuj. Jeśli skracasz kod, istnieje bardzo duże prawdopodobieństwo, że otrzymasz nieprawidłowy kod kraju.
coderjoe
W przypadku większości aplikacji dane są sprawdzane przed wysłaniem ich do bazy danych ...
Cobby
2
Pewnie. Większość. Ale czuję, że tutaj zakładasz, że programista, który tworzy nową aplikację dla istniejącej bazy danych, jest świadomy ograniczeń dotyczących danych (nie wszyscy jesteśmy ekspertami w zakresie każdego rodzaju danych i tego, jak są one wdrażane w każdej bazie danych ). To, że możesz zweryfikować dane w swojej aplikacji, nie oznacza, że ​​to zrobiłeś.
shufler
3
the design documentation (which surely exists)Hah. : D
Camilo Martin
14

Jestem z tobą. Precyzyjna dbałość o szczegóły jest uciążliwa i ma ograniczoną wartość.

Kiedyś dysk był cennym towarem i zwykliśmy pocić się, aby go zoptymalizować. Cena przechowywania spadła 1000-krotnie, przez co czas spędzony na wyciskaniu każdego bajtu jest mniej cenny.

Jeśli używasz tylko pól CHAR, możesz uzyskać wiersze o stałej długości. Może to zaoszczędzić trochę rzeczywistego przekształcenia dysku, jeśli wybrałeś dokładne rozmiary pól. Możesz uzyskać bardziej gęsto upakowane dane (mniej we / wy dla skanów tabel) i szybsze aktualizacje (łatwiejsze do zlokalizowania otwartych przestrzeni w bloku dla aktualizacji i wstawień).

Jeśli jednak przeszacujesz swoje rozmiary lub rzeczywiste rozmiary danych są zmienne, stracisz miejsce na pola CHAR. Dane będą mniej gęsto upakowane (co prowadzi do większej liczby wejść / wyjść dla dużych pobrań).

Ogólnie rzecz biorąc, korzyści w zakresie wydajności wynikające z próby umieszczenia rozmiaru na zmiennych zmiennych są niewielkie. Możesz łatwo wykonać test porównawczy, używając VARCHAR (255) w porównaniu z CHAR (x), aby sprawdzić, czy możesz zmierzyć różnicę.

Czasami jednak muszę podać „małą”, „średnią”, „dużą” wskazówkę. Więc używam 16, 64 i 255 dla rozmiarów.

S.Lott
źródło
13

W dzisiejszych czasach nie mogę sobie wyobrazić, że to naprawdę ma znaczenie.

Korzystanie z pól o zmiennej długości wiąże się z obciążeniem obliczeniowym, ale przy dzisiejszym nadmiarze procesorów nie jest to warte rozważenia. Systemy I / O są tak powolne, że nie istnieją żadne koszty obliczeniowe związane z efektywną obsługą varcharów. W rzeczywistości, obliczeniowo cena varchar jest prawdopodobnie wygraną netto w stosunku do ilości zaoszczędzonej przestrzeni dyskowej dzięki zastosowaniu pól o zmiennej długości na polach o stałej długości. Najprawdopodobniej masz większą gęstość rzędów.

Złożoność pól varchar polega na tym, że nie można łatwo zlokalizować rekordu na podstawie jego numeru. Kiedy masz rozmiar wiersza o stałej długości (z polami o stałej długości), obliczenie bloku dysku, na który wskazuje identyfikator wiersza, jest trywialne. Przy zmiennej długości wiersza, ten rodzaj wychodzi przez okno.

Więc teraz musisz zachować jakiś indeks numeru rekordu, tak jak każdy inny klucz podstawowy, LUB musisz utworzyć solidny identyfikator wiersza, który koduje szczegóły (takie jak blok itp.) Do identyfikatora. Jeśli to zrobisz, identyfikator będzie musiał zostać ponownie obliczony, jeśli kiedykolwiek wiersz zostanie przeniesiony do pamięci trwałej. Nic wielkiego, wystarczy przepisać wszystkie wpisy indeksu i upewnić się, że a) nigdy nie ujawniasz tego konsumentowi lub b) nigdy nie twierdzisz, że liczba jest wiarygodna.

Ale ponieważ mamy dzisiaj pola varchar, jedyną wartością varchar (16) w porównaniu z varchar (255) jest to, że DB wymusi ograniczenie 16 znaków na varchar (16). Jeśli model bazy danych ma być rzeczywiście reprezentatywny dla fizycznego modelu danych, wtedy posiadanie długości pól może mieć wartość. Jeśli jednak jest to po prostu „przechowywanie”, a nie „model ORAZ przechowywanie”, nie ma takiej potrzeby.

Następnie wystarczy rozróżnić między polem tekstowym, które jest indeksowalne (takie varchar), a czymś, co nie jest (jak pole tekstowe lub pole CLOB). Indeksowalne pola mają zwykle ograniczenie rozmiaru, aby ułatwić indeksowanie, podczas gdy pola CLOB nie (w granicach rozsądku).

Will Hartung
źródło
5

Z mojego doświadczenia wynika, że ​​jeśli pozwolisz na typ danych o długości 255 znaków, jakiś głupi użytkownik (lub jakiś doświadczony tester) faktycznie to wypełni.

Następnie masz różnego rodzaju problemy, w tym ilość miejsca przeznaczonego na te pola w raportach i wyświetlanych na ekranie aplikacji. Nie wspominając o możliwości przekroczenia limitu na wiersz danych w Twojej bazie danych (jeśli masz więcej niż kilka z tych 255 znaków).

Znacznie łatwiej jest wybrać rozsądny limit na początku, a następnie wymusić go za pośrednictwem aplikacji i bazy danych.

BradC
źródło
0

Dobrą praktyką jest przydzielanie tylko trochę ponad to, czego potrzebujesz. Numery telefonów nigdy nie byłyby tak duże.

Jednym z powodów jest to, że jeśli nie przeprowadzisz walidacji pod kątem dużych wpisów, bez wątpienia ktoś użyje wszystkiego, co jest. Wtedy może zabraknąć miejsca w rzędzie. Nie jestem pewien co do limitu MySQL, ale 8060 to maksymalny rozmiar wiersza w MS SQL.

Bardziej normalna wartość domyślna to 50 imho, a następnie zwiększanie w razie potrzeby.

gołąb
źródło
Dzięki. Zdecydowanie zgadzam się, że to dobra praktyka. To aspekt wydajności, który bardzo chciałbym wyjaśnić
Olly
0

W kontekście mysql może to stać się ważne podczas pracy z indeksami we wspomnianych kolumnach varchar, ponieważ mysql ma max. limit 767 bajtów na wiersz indeksu.

Oznacza to, że dodając indeks w kilku kolumnach varchar 255 można dość szybko / jeszcze szybciej osiągnąć ten limit na kolumnach utf8 lub utf8mb4, jak wskazano w odpowiedziach powyżej

staabm
źródło