Wpływ na wydajność rozmiarów VARCHAR MySQL

45

Czy istnieje różnica w wydajności MySQL między rozmiarami varchar? Na przykład varchar(25)i varchar(64000). Jeśli nie, to czy istnieje powód, aby nie deklarować wszystkich varcharów o maksymalnym rozmiarze tylko po to, aby nie zabrakło Ci miejsca?

BenV
źródło
3
+1 to pytanie dotyczy wszystkich DBMS. Moja obserwacja ma tendencję do wzrostu wielu rozmiarów varcharów.
bernd_k
5
Nie MySQL, ale ten post na blogu napisany przez Depesz może odpowiedzieć na twoje pytanie dotyczące PostgreSQL .
ksenoterrakid

Odpowiedzi:

29

Musisz zdać sobie sprawę z kompromisów używania CHAR vs VARCHAR

W przypadku pól CHAR alokujesz dokładnie to, co dostajesz. Na przykład CHAR (15) przydziela i przechowuje 15 bajtów, bez względu na to, jak postacie umieszczasz w polu. Manipulowanie ciągami znaków jest proste i jednoznaczne, ponieważ wielkość pola danych jest całkowicie przewidywalna.

Dzięki polom VARCHAR otrzymujesz zupełnie inną historię. Na przykład VARCHAR (15) faktycznie dynamicznie przydziela do 16 bajtów, do 15 na dane i co najmniej 1 dodatkowy bajt do przechowywania długości danych. Jeśli masz ciąg „hello” do zapisania, który zajmie 6 bajtów, a nie 5. Manipulowanie ciągiem zawsze musi przeprowadzać sprawdzanie długości we wszystkich przypadkach.

Kompromis jest bardziej widoczny, gdy wykonujesz dwie rzeczy:
1. Przechowywanie milionów lub miliardów wierszy
2. Indeksowanie kolumn, które są albo CHAR albo VARCHAR

TRADEOFF # 1

Oczywiście VARCHAR ma tę zaletę, że dane o zmiennej długości utworzyłyby mniejsze wiersze, a tym samym mniejsze pliki fizyczne.

TRADEOFF # 2

Ponieważ pola CHAR wymagają mniejszej manipulacji ciągiem ze względu na stałe szerokości pól, wyszukiwanie indeksów względem pola CHAR jest średnio o 20% szybsze niż w przypadku pól VARCHAR. To nie jest żadna hipoteza z mojej strony. Książka MySQL Database Design and Tuning wykonała coś cudownego na stole MyISAM, aby to udowodnić. Przykład w książce zrobił coś takiego:

ALTER TABLE tblname ROW_FORMAT=FIXED;

Ta dyrektywa zmusza VARCHAR do zachowywania się jak CHAR. Zrobiłem to podczas mojej poprzedniej pracy w 2007 roku i wziąłem tabelę 300 GB i przyspieszyłem wyszukiwanie indeksów o 20%, nie zmieniając niczego innego. Działa jak opublikowano. Jednak stworzył stół prawie dwukrotnie większy, ale to po prostu wraca do kompromisu nr 1.

Możesz przeanalizować przechowywane dane, aby zobaczyć, co MySQL zaleca do definicji kolumny. Po prostu uruchom następujące polecenie dla dowolnej tabeli:

SELECT * FROM tblname PROCEDURE ANALYSE();

Spowoduje to przejście całej tabeli i zalecenie definicji kolumn dla każdej kolumny na podstawie zawartych w niej danych, minimalnych wartości pól, maksymalnych wartości pól i tak dalej. Czasami musisz po prostu zachować zdrowy rozsądek przy planowaniu CHAR vs VARCHAR. Oto dobry przykład:

Jeśli przechowujesz adresy IP, maska ​​takiej kolumny ma maksymalnie 15 znaków (xxx.xxx.xxx.xxx). W mgnieniu oka przeskoczyłbym na CHAR (15), ponieważ długości adresów IP nie będą się tak bardzo różnić, a dodatkowa złożoność operacji na łańcuchach kontrolowana przez dodatkowy bajt. Nadal można wykonać ANALIZĘ PROCEDURY () przeciwko takiej kolumnie. Może nawet polecić VARCHAR. W tym przypadku moje pieniądze byłyby nadal na CHAR zamiast VARCHAR.

Problemy z CHAR vs VARCHAR można rozwiązać tylko poprzez odpowiednie planowanie. Z wielką mocą wiąże się wielka odpowiedzialność (banał, ale prawda)

RolandoMySQLDBA
źródło
4
Jeśli przechowujesz adresy IP, nie widzę powodu, aby przechowywać je jako coś innego niż int. To wszystko adres IP. Wiele języków ma jakąś funkcję ip2int. Jeśli chcesz konwergencji wywołania z wiersza poleceń, nie jest trudno wykonać procedurę składowaną do konwersji ABCD: A pow (256,3) + b pow (256,2) + c * 256 + d
atxdba 18.10.11
1
Bardziej do tego stopnia, myślę, że mysql ma swoją własną funkcję ip2int: INET_ATON
atxdba 18.10.11
3
@atxdba: Istotą mojej odpowiedzi jest po prostu użycie CHAR vs VARCHAR. Po prostu używam IP jako przykładu, ponieważ jego wielkość ciągu znaków jest bliższa 15. Zatem zaokrąglenie stabilnego rozmiaru CHAR na korzyść VARCHAR jest tylko przykładem ze względu na samo pytanie. Twój komentarz na temat lepszych sposobów reprezentowania adresów IP jest dość trafny i najbardziej sensowny.
RolandoMySQLDBA
CHAR (15) przydziela 15 znaków , a nie bajtów . Dla utf8 jest to 45 bajtów .
Rick James,
2
Chociaż jest to dobra odpowiedź na temat porównania CHAR / VARCHAR, pytanie dotyczyło różnych rozmiarów VARCHAR.
Collector
13

Odpowiedź na to pytanie jest w rzeczywistości dość złożona. Krótka wersja: jest różnica .

  1. Podczas tworzenia tabel tymczasowych w celu filtrowania wyników (np. GROUP BYInstrukcji) zostanie przydzielona pełna długość.

  2. Protokół przewodowy (wysyłanie wierszy do klienta) prawdopodobnie przydzieli większą długość.

  3. Silnik pamięci może / nie może implementować prawidłowego varchara.

W przypadku (2) przyznaję, że protokół przewodowy nie jest czymś, z czym jestem ściśle zaznajomiony, ale ogólna rada tutaj jest próba podjęcia przynajmniej minimalnego wysiłku, aby odgadnąć długość.

Morgan Tocker
źródło
Warto zwrócić uwagę. MySQL 5.7 może pakować wartości w buforze sortowania (o zmiennej długości). Bardziej szczegółowo wyjaśnione tutaj: mysqlserverteam.com/…
Morgan Tocker
9

Większość odpowiedzi w tym wątku ma 5 lat, napisanych przed InnoDB i utf8. Więc zacznę od nowa ...

Gdy zapytanie potrzebuje wewnętrznej tabeli tymczasowej, próbuje użyć MEMORYtabeli. Ale PAMIĘCI nie można użyć, jeśli

  • TEXT/ BLOBkolumny są pobierane, nawet nie TINYTEXT.
  • VARCHAR większa niż pewna ilość, prawdopodobnie 512 w obecnej wersji.

Zauważ też, że VARCHARssą zamienione CHARs. Zatem VARCHAR(255)z CHARACTER SET utf8rozszerzeniem do 765 bajtów, niezależnie od tego, co znajduje się w kolumnie. Następnie może to zostać uruchomione:

  • Jeśli MEMORYtabela będzie większa niż jedna z nich max_heap_table_size lub tmp_table_size , zostanie przekonwertowana na MyISAM i potencjalnie rozlana na dysk.

Jest więc VARCHAR(25)bardziej prawdopodobne, że zostanie MEMORY, dlatego będzie szybszy. (255)nie jest tak dobry i (64000)jest zły.

(W przyszłości prawdopodobnie będą to tabele tymczasowe InnoDBi część tej odpowiedzi będzie wymagać korekty).

Rick James
źródło
6

Rozmiar kolumny varchar sprawia, że ​​zapytania w całej tabeli częściej korzystają z tabel tymczasowych. Według książki o wysokiej wydajności MySQL. Gdy optymalizator próbuje sprawdzić, czy może uruchomić to zapytanie w pamięci lub czy potrzebuje tabeli tymczasowej, sprawdza rozmiar wiersza na podstawie definicji tabeli, co oznacza, że ​​dla prędkości nie próbuje sprawdzić, ile znaków ma 64K faktycznie używasz. Dlatego autorzy zalecają, aby nie rozciągać tej definicji daleko poza rzeczywiste możliwe wartości, które byłyby w kolumnie. Oczywiście, jeśli zdecydujesz się na więcej zapytań przechodzących do tabel tymczasowych (nawet jeśli rzeczywisty rozmiar danych może zmieścić się w pamięci RAM), poniosłeś teraz kary we / wy, których mogłeś uniknąć.

TechieGurl
źródło
To bardzo świeże spojrzenie. Jeśli jest to książka, do której się odwołujesz ( amazon.com/MySQL-High-A Availability-Building-Centers / dp/… ), proszę podać numer strony książki w swojej odpowiedzi, ponieważ chciałbym ją przeczytać. +1 !!!
RolandoMySQLDBA,
Silly ja… Wysoka WYDAJNOŚĆ niedostępność: amazon.com/High-Performance-MySQL-Optimization-Replication/dp/…… numer strony to 236/237 Wyjaśnia, jak hojność przy definiowaniu kolumny varchar może być nierozsądna. Pamiętaj jednak, że ta książka została napisana, gdy wersja 5.1 właśnie została wydana. Trzecia edycja wychodzi w przyszłym roku obejmują wszystkie duże zmiany w 5.5 więc może to się zmieni :)
TechieGurl
Strona 236 wspomina o sortowaniu należącym do poszczególnych zestawów znaków. To może być paskudne dla VARCHARA. Na stronie 237 Ustawienia komunikacji klient / serwer wraz z rysunkiem 5-5 na stronie 238 wskazują inny powód. Proces tłumaczenia znaków odbywa się tam iz powrotem. Znów kolejna paskudna przygoda dla VARCHAR.
RolandoMySQLDBA,
Aby to wyjaśnić, chociaż ta sekcja nie mówi wprost, że MySQL przejdzie do tworzenia rozmiaru, wiemy, że gdy operacja potrzebuje tabeli tymczasowej, ta tabela znajduje się w MEMORY Engine i TO zawsze przechowuje typy łańcuchów w porcjach poprawek, więc tak hojny definicja może spowodować, że potrzebna tabela temp MEMORY przejdzie na dysk w przeciwieństwie do pozostawania w pamięci RAM
TechieGurl
@RolandoMySQLDBA. Tak ... to też ... zestawienie również staje się tutaj czynnikiem (szczególnie jeśli używasz UTF-8 i nie masz znaków łacińskich) i wszystko to po prostu zabija cię, gdy masz do czynienia z tabelą silnika pamięci i prowadzi do szybszej podróży na dysk
TechieGurl
5

Rozumiem, że mniejsze pola mogą być bezpośrednio włączone do indeksu, podczas gdy dłuższe nie. Z powodu tego ograniczenia, jeśli chcesz, aby ciągi były indeksowane, powiedziałbym, że powinny być krótsze. W przeciwnym razie nie, ponieważ oba są varchar, a następnie operacje sortowania lub porównywania będą działać w tym samym czasie, niezależnie od tego, czy pola mają 25, czy MAX.

jcolebrand
źródło
3

upewnij się, że nie zabraknie Ci miejsca

Ta fraza sugeruje, że zadajesz pytanie, ponieważ nie masz pewności co do danych, które będziesz przechowywać w bazie danych. Jeśli to prawda, będziesz dobrze poinformowany, aby dowiedzieć się jak najszybciej, ponieważ będziesz go potrzebować do planowania wydajności. Jeśli na przykład otrzymujesz elementy danych zawierające 7000 znaków, musisz wiedzieć, ponieważ miałoby to wpływ na wydajność dowolnego DBMS.

To powiedziawszy, wolę mieć rozmiary kolumn związane z oczekiwaną zawartością. Na przykład numer telefonu nie może być dłuższy niż 50 znaków, nawet jeśli podasz kod kraju i numer wewnętrzny. Podobnie kod pocztowy lub pocztowy najprawdopodobniej będzie miał 20 znaków lub mniej.

Larry Coleman
źródło