MySQL: Large VARCHAR vs. TEXT?

845

Mam tabelę komunikatów w MySQL, która rejestruje wiadomości między użytkownikami. Oprócz typowych identyfikatorów i typów wiadomości (wszystkie typy całkowite) muszę zapisać rzeczywisty tekst wiadomości jako VARCHAR lub TEXT. Ustawiam limit frontonu na 3000 znaków, co oznacza, że ​​wiadomości nigdy nie będą wstawiane do bazy danych tak długo.

Czy istnieje uzasadnienie dla korzystania z VARCHAR (3000) lub TEXT? W pisaniu VARCHAR (3000) jest coś, co wydaje się nieco sprzeczne z intuicją. Przejrzałem inne podobne posty na temat Przepełnienia stosu, ale dobrze byłoby uzyskać widoki specyficzne dla tego rodzaju przechowywania typowych wiadomości.

Tomek
źródło
27
Trochę stary, ale przyjechałem tutaj, ponieważ napotkałem problem, który zmusił mnie do myślenia o tym. W moim przypadku moja forma interfejsu była ograniczona do 2000 znaków, ale kodowanie niejawne w mojej metodzie przechowywania zakodowało znaki międzynarodowe jako wiele znaków (które najwyraźniej mogą zawierać od 3 do 12 znaków na znak). Tak więc moje 2000 nagle wzrasta do 24 000. Coś do przemyślenia ...
James S
3
Przekonałem się, że tekst jest znacznie szybszy dla wielu współbieżnych wstawek.
Ray S.
1
@JamesS: utf8mb4 ...>. <
niepodzielny
10
@RickJames rozważa opublikowanie zaktualizowanej odpowiedzi, zamiast zamknąć pytanie
Yvette
3
@YvetteColomb - dodałem odpowiedź. Chciałbym głównie pozbyć się odpowiedzi zaakceptowanej, ponieważ jest nieaktualna . Przyszedłem do pytania i odpowiedzi, ponieważ ktoś cytował nieprawidłowe informacje, mówiąc: „754 głosy poparcia, więc to musi być poprawne”. OK, zredagowałem również Zatwierdzoną odpowiedź. (Choć wydaje się to niewłaściwe.)
Rick James

Odpowiedzi:

811
  • TEXTi BLOB może być przechowywany poza stołem, przy czym stół ma tylko wskaźnik do lokalizacji rzeczywistej pamięci. Miejsce przechowywania zależy od wielu rzeczy, takich jak rozmiar danych, rozmiar kolumn, format_wierszy i wersja MySQL.

  • VARCHARjest przechowywany w jednej linii z tabelą. VARCHARjest szybszy, gdy rozmiar jest rozsądny, którego kompromis byłby szybszy, zależy od twoich danych i sprzętu, chciałbyś przetestować rzeczywisty scenariusz z twoimi danymi.

MindStalker
źródło
148
+1: VARCHAR (przechowywany wbudowany) jest zwykle szybszy, JEŚLI dane są często pobierane (uwzględniane przez większość zapytań). Jednak w przypadku dużej ilości danych, które normalnie nie są pobierane (tzn. Które nie są przywoływane przez żadne zapytanie), lepiej nie mieć danych przechowywanych bezpośrednio. Istnieje górna granica wielkości wiersza dla danych przechowywanych w wierszu.
spencer7593
21
@Pacerier: dokładną korzyścią z unikania „wbudowanego” przechowywania jest zwiększenie liczby wierszy, które mogą być przechowywane w bloku, co oznacza, że ​​wiersze tabeli zajmują mniej bloków w pamięci podręcznej bufora InnoDB (mniejszy ślad pamięci) i oznaczają mniej bloki do przeniesienia na iz dysku (zmniejszone I / O). Jest to jednak tylko korzyść w zakresie wydajności, jeśli zapytania przechowywane w kolumnach „poza wierszem” są w dużym stopniu niepowiązane. Jeśli większość zapytań odnosi się do tych kolumn „poza wierszem”, korzyści w dużej mierze wyparowują. Opcja Inline jest preferowana, jeśli kolumny mieszczą się w maksymalnym rozmiarze wierszy i są często przywoływane.
spencer7593
231
„VARCHAR jest szybszy, gdy rozmiar jest rozsądny”. Co to jest „rozsądna” liczba znaków, 100? 1000? 100 000?
tim peterson
125
Ta odpowiedź jest nieprawidłowa dla InnoDB. Zarówno VARCHAR, jak i BLOB / TEXT są przechowywane w jednej linii z innymi kolumnami, jeśli wartość w danym wierszu mieści się w rozmiarze strony (16 KB i każda strona musi zawierać co najmniej dwa wiersze). Jeśli ciąg jest na to zbyt duży, przepełnia dodatkowe strony. Zobacz mysqlperformanceblog.com/2010/02/09/blob-storage-in-innodb do szczegółowego wyjaśnienia.
Bill Karwin
14
@BillKarwin ... Jeśli mam zrozumienia poprawnie to nie powinno być żadnej różnicy między wydajność varchari blob/ textna InnoDB dla małych elementów tekstowych? Więc byłoby wtedy być mądry po prostu dołożyć wszelkich varchardo textrodzaju i niech DB zarządzać inline vs przepełnienia?
ryvantage
473

Czy potrafisz przewidzieć, jak długo potrwa wkład użytkownika?

VARCHAR (X)

Przypadek: nazwa użytkownika, adres e-mail, kraj, temat, hasło


TEKST

Case: wiadomości, e-maile, komentarze, sformatowany tekst, HTML, kod, obrazy, linki


MEDIUMTEXT

Obudowa: duże ciała Jsona, książki od krótkiej do średniej długości, ciągi CSV


LONGTEXT

Przypadek: podręczniki, programy, lata plików z logami, Harry Potter i Czara Ognia, rejestracja badań naukowych

Michael J. Calkins
źródło
7
Przewidywalność jest tutaj naprawdę elementem pobocznym. W rzeczywistości decydująca jest maksymalna oczekiwana długość. Przedmioty, które wymieniasz jako bardziej przewidywalne, są tylko w ten sposób, ponieważ są krótsze niż inne.
Andrew Barber,
29
@ andrew-fryzjer To jednak mój punkt widzenia. Wszystkie pozostałe posty dobrze wyjaśniają różnice, ale nie sytuacje, w których musisz dokonać wyboru między nimi. Próbowałem wskazać, że używanie varchar jako przewidywalnie krótkiego jest dobrym wyborem, a używanie tekstu przez dowolnie długi czas jest dobrym wyborem.
Michael J. Calkins,
1
Jeśli wszystkie kolumny są krótkie i przewidywalne (np. Adres MAC, IMEI itp. ... to rzeczy, które nigdy się nie zmieniają), użyj kolumn CHAR i możesz ustawić swój rozmiar wiersza, co powinno znacznie przyspieszyć, jeśli używasz MyISAM, być może także InnoDb, chociaż nie jestem tego pewien.
Matt
1
@ MichaelJ.Calkins Thing, które wydarzyło się w MySQL 5.6. Teraz masz także wyszukiwanie pełnotekstowe w InnoDB. Zobacz dev.mysql.com/doc/refman/5.6/en/fulltext-search.html
PhoneixS
7
Limity znaków: TINYTEXT: 255; TEKST: 65 535; ŚREDNIOTekst: 16,777,215; DŁUGI TEKST: 4,294,967,29.
Victor Stoddard
218

Aby wyjaśnić najlepsze praktyki:

  1. Wiadomości w formacie tekstowym powinny prawie zawsze być przechowywane jako TEKST (kończą się dowolnie długimi)

  2. Atrybuty ciągów powinny być przechowywane jako VARCHAR (docelowa nazwa użytkownika, temat itp.).

Rozumiem, że masz limit frontonu, który jest świetny, dopóki go nie ma. * grin * Sztuczka polega na tym, aby myśleć o DB jako oddzielnym od aplikacji, które się z nią łączą. To, że jedna aplikacja ogranicza dane, nie oznacza, że ​​dane są wewnętrznie ograniczone.

Co takiego jest w samych wiadomościach, że zmusza je, aby nigdy nie miały więcej niż 3000 znaków? Jeśli jest to tylko arbitralne ograniczenie aplikacji (np. W przypadku pola tekstowego lub czegoś innego), użyj TEXTpola na warstwie danych.

James
źródło
Co znaczy „co jest wspaniałe, dopóki nie jest”? Czego dotyczy słowo „nie”?
Pacerier
7
@Pacerier Aby dać ci przykład „nie” James prawdopodobnie mówi o: Weźmy na przykład Twittera, który do niedawna miał limit 140 znaków na PM. Uznali, że to już nie jest rozsądne i postanowili całkowicie usunąć ten limit. Gdyby nie zastanawiali się nad tym (co jestem pewien, że prawdopodobnie tak zrobili ...) wpadliby w scenariusz opisany powyżej.
PaulSkinner,
9
Właśnie zakładam naszą nową bazę danych i założyłem, że nikt nie mógłby umieścić więcej niż 2000 znaków w naszych małych polach komentarzy, a potem, jak zauważa James, dzisiejszej nocy nagle „nie było w porządku”, ponieważ użytkownik przejrzał bardzo ważny komentarz o długości 2600 znaków. Użyłem varchar (2000), myśląc, że to nie może trwać dłużej, i się myliłem. więc tak, jest świetnie, dopóki nie będzie. W naszym przypadku zajęło to tylko kilka dni. Reguła poniżej, Michael J. Calkins, myślę, że odtąd będę korzystać. tekst wiadomości, komentarze.
Lizardx
1
@Pacerier „co jest świetne, dopóki nie jest świetne”. Innymi słowy, działa prawie cały czas i jest cudowny ... z wyjątkiem wyjątkowych sytuacji, w których nie jest tak świetny.
Ograniczone Zadośćuczynienie
@Pacerier w komentarzach do wybranej odpowiedzi wspomniany jest inny interesujący przykład, w zasadzie miał on limit 2000 znaków, ale wprowadzone znaki były na stronie kodowej, która w rzeczywistości używała więcej bajtów niż zwykłych liter, jego baza danych ostatecznie wymagała miejsca dla 24 000 znaków tylko dlatego, że musiał uwzględnić rzeczywisty rozmiar bajtów wprowadzanych znaków.
RaptorX
32

Oświadczenie: Nie jestem ekspertem od MySQL ... ale to moje rozumienie problemów.

Myślę, że TEKST jest przechowywany poza wierszem mysql, podczas gdy myślę, że VARCHAR jest przechowywany jako część tego wiersza. Istnieje maksymalna długość wiersza dla wierszy mysql .. więc możesz ograniczyć ilość innych danych, które możesz przechowywać w rzędzie, używając VARCHAR.

Również ze względu na to, że VARCHAR stanowi część wiersza, podejrzewam, że zapytania dotyczące tego pola będą nieco szybsze niż te, które używają fragmentu TEXT.

Michael Anderson
źródło
38
Limit długości wiersza wynosi 65 535 bajtów [ dev.mysql.com/doc/refman/5.0/en/column-count-limit.html ]. Jeśli twoja kolumna jest zakodowana w utf8, oznacza to, że varcharkolumna zawierająca 3000 znaków może zająć do 9000 bajtów.
Jan Fabry
7
Znaki UTF-8 mogą mieć do 4 bajtów, więc myślę, że chodziło o 12 000 bajtów (chyba, że ​​jest coś, czego nie rozumiem w MySQL).
raylu
13
@raylu UTF-8 MySQL jest „fałszywym UTF-8”, ponieważ obsługuje tylko 3 bajty na maksimum znaku, więc nie ma możliwości bezpośredniego przechowywania znaków Unicode poza płaszczyzną BMP w UTF-8 MySQL. Zostało to naprawione w MySQL 5.5.
Pacerier,
2
Uważam, że to twierdzenie jest ważne tylko dla MyISAM. Nie mogę znaleźć ostatecznego źródła, ale uważam, że InnoDB przechowuje również TEXTwbudowane w tabeli.
dotancohen
2
@dotancohen Znalazłem tutaj źródło wyjaśniające, że przechowywanie danych o zmiennej długości za pomocą InnoDB może się różnić (może być przechowywane zewnętrznie lub wewnątrz wiersza) mysqlserverteam.com/externally-stored-fields-in-innodb
KiX Ortillan
30

Krótka odpowiedź: brak praktycznej, wydajności lub przechowywania, różnica.

Długa odpowiedź:

Zasadniczo nie ma różnicy (w MySQL) między VARCHAR(3000)(lub innym dużym limitem) a TEXT. Pierwszy z nich obetnie 3000 znaków ; ten ostatni zostanie obcięty przy 65535 bajtach . (I rozróżnia bajtów i znaków , ponieważ postać może wziąć kilka bajtów).

Dla mniejszych limitów w VARCHAR istnieją pewne zalety TEXT.

  • „mniejszy” oznacza 191, 255, 512, 767 lub 3072 itd., w zależności od wersji, kontekstu i CHARACTER SET.
  • INDEXessą ograniczone w tym, jak duża może być indeksowana kolumna. (767 lub 3072 bajtów ; jest to zależne od wersji i ustawień)
  • Tabele pośrednie utworzone przez kompleks SELECTssą obsługiwane na dwa różne sposoby - MEMORY (szybciej) lub MyISAM (wolniej). Gdy w grę wchodzą „duże” kolumny, wolniejsza technika jest wybierana automatycznie. (Znaczące zmiany w wersji 8.0; więc ten punktor może ulec zmianie).
  • W odniesieniu do poprzedniego elementu wszystkie TEXTtypy danych (w przeciwieństwie do VARCHAR) przechodzą bezpośrednio do MyISAM. Oznacza to, że TINYTEXTautomatycznie jest gorszy dla wygenerowanych tabel temperatur niż ich odpowiednik VARCHAR. (Ale to prowadzi dyskusję w trzecim kierunku!)
  • VARBINARYjest jak VARCHAR; BLOBjest jak TEXT.

Obalenie innych odpowiedzi

Pierwotne pytanie zawierało jedno pytanie (jakiego typu danych użyć); zaakceptowana odpowiedź odpowiedziała na coś innego (zapisywanie poza rekordem). Ta odpowiedź jest już nieaktualna.

Kiedy ten wątek został uruchomiony i odpowiedział, w InnoDB istniały tylko dwa „formaty wierszy”. Niedługo potem dwa kolejne formaty ( DYNAMICiCOMPRESSED ).

Miejsce przechowywania TEXTi VARCHAR()zależy od rozmiaru , a nie od nazwy typu danych . Aby uzyskać zaktualizowaną dyskusję na temat przechowywania / zapisywania w trybie zapisu dużych kolumn tekstu / obiektów blob, zobacz to .

Rick James
źródło
1
Dobry wgląd tutaj. To powinna być zaakceptowana odpowiedź.
Kosta Kontos
2
@KostaKontos - Dzięki za pochwałę i poprawkę literówek. Kiedy widzę potrzebę lepszej odpowiedzi, dodam odpowiedź, nawet jeśli 8 lat i 800 głosów za późno.
Rick James
7

W poprzednich odpowiedziach nie nalegano wystarczająco na główny problem: nawet w bardzo prostych zapytaniach, takich jak

(SELECT t2.* FROM t1, t2 WHERE t2.id = t1.id ORDER BY t1.id) 

może być wymagana tabela tymczasowa, a jeśli VARCHARpole jest zaangażowane, jest konwertowane na CHARpole w tabeli tymczasowej. Więc jeśli masz w tabeli powiedz 500 000 linii z VARCHAR(65000)polem, sama kolumna użyje 6,5 * 5 * 10 ^ 9 bajtów. Takie tabele tymczasowe nie mogą być obsługiwane w pamięci i są zapisywane na dysku. Można oczekiwać, że wpływ będzie katastrofalny.

Źródło (z metrykami): https://nicj.net/mysql-text-vs-varchar-performance/ (Odnosi się to do obsługi TEXTvs VARCHARw „standardowym” (?) Silniku pamięci MyISAM. W innych może być inaczej, np. InnoDB.)

Max
źródło
3
InnoDB: To samo dotyczy wersji 5.7. W wersji 8.0 szablony varchar mają zmienną długość.
Rick James
3

Istnieje OGROMNA różnica między VARCHAR a TEKSTEM. Podczas gdy pola VARCHAR mogą być indeksowane, pola TEXT nie. Pola typu VARCHAR są przechowywane w linii, podczas gdy TEKST jest przechowywany w trybie offline, w rzeczywistości zapisywane są tylko wskaźniki do danych TEKSTU.

Jeśli musisz zaindeksować swoje pole w celu szybszego wyszukiwania, zaktualizuj lub usuń niż przejdź do VARCHAR, bez względu na to, jak duże. VARCHAR (10000000) nigdy nie będzie taki sam jak pole TEXT, ponieważ te dwa typy danych mają różny charakter.

  • Jeśli korzystasz z pola tylko do archiwizacji
  • nie zależy ci na wycofywaniu prędkości danych
  • zależy Ci na szybkości, ale w zapytaniu użyjesz operatora „% LIKE%”, więc indeksowanie niewiele pomoże
  • nie można przewidzieć limitu długości danych

niż iść do TEKSTU.

Viktor Joras
źródło
Informacje częściowo wprowadzające w błąd: kolumn TEXT nie można indeksować w całości. Gdy do indeksu dołączasz kolumnę TEKST, musisz określić długość. Również VARCHAR nie mogą być indeksowane w całości w przypadku VARCHAR> 255, ponieważ rozmiar indeksu ma maksymalną długość.
eRadical
2

Varchar jest przeznaczony do małych danych, takich jak adresy e-mail, natomiast Text do znacznie większych danych, takich jak artykuły prasowe, Blob do danych binarnych, takich jak obrazy.

Wydajność Varchar jest większa, ponieważ działa całkowicie z pamięci, ale nie będzie tak, jeśli dane są zbyt duże, jak varchar(4000)na przykład.

Z drugiej strony, tekst nie przylega do pamięci i ma wpływ na wydajność dysku, ale można tego uniknąć, oddzielając dane tekstowe w osobnej tabeli i stosując zapytanie o lewe połączenie w celu pobrania danych tekstowych.

Kropelka jest znacznie wolniejsza, więc używaj jej tylko wtedy, gdy nie masz zbyt wielu danych, takich jak 10000 obrazów, które kosztują 10000 rekordów.

Postępuj zgodnie z tymi wskazówkami, aby uzyskać maksymalną prędkość i wydajność:

  1. Użyj varchar do imienia, tytułów, e-maili

  2. Użyj tekstu dla dużych danych

  3. Oddziel tekst w różnych tabelach

  4. Użyj zapytań Left Join o identyfikatorze, takim jak numer telefonu

  5. Jeśli zamierzasz użyć obiektu Blob, zastosuj te same wskazówki, co w tekście

Spowoduje to, że zapytania będą kosztować milisekundy w tabelach z danymi> 10 M i rozmiarem do 10 GB.

Creative87
źródło