Autor Zpráva
tester
Profil *
Chtěl jsem se zeptat jaký je v těch dvou typech rozdíl, ale aby se neřeklo koukl jsem do manuálu a tam se píše:

Use of disk incurs a performance penalty, so include BLOB or TEXT columns in the query result only if they are really needed. For example, avoid using SELECT *, which selects all columns.

Proč se ptám. Napadlo mě proč se dává do tabulky uživatelů heslo typu varchar(32). Proč ne text? Ušetřilo by se místo. Pokud se uživatel přihlašuje jen jednou, je nějaký důvod proč tam nedát text a neušetřit tak místo? Případně rovnou i na sloupec email. Byl by ten výkon opravdu tak znát, že z např. 10.000 záznamů bychom čekali 5-10 sekund než mysql vrátí výsledek? Kdysi jsem dělal správce diskusního fora a když jsem hledal např. spamové adresy v komentářích, kterých určitě nebylo málo, tak pomocí LIKE to našel prakticky okamžitě. Tak co bych tím mohl ušetřit, mělo by to význam?

Podotázka týkající se BLOBu. Zajímalo by mě jestli je možné vytvořit číselný typ o velikosti 1 byte. Když dám INT(1) je to jeden byte nebo se to stále počítá podle OS? Jako že 4 byte na 32bit OS a 8 byte na 64bit OS? S tím právě souvisí má myšlenka zda by se BLOB(1) (1 byte) dal použít na SQLite k tomu abych neplýtval místem když potřebuju zapsat hodnotu v rozsahu 0-255. Mohl bych použít BLOB, ale když bych pak chtěl uplatnit porovnávací masku (dá se to vůbec v SQLite?) tak by nejspíš byl zpomalený výkon? Např. chci procházet tabulku s uživateli a najít porovnáváním zadané hodnoty/masky s údaji v tabulce. Dejme tomu příklad žena hledá muž s určitými parametry, nekuřáka, atd. a to tam všechno v tom jednom bytu je. Bylo by to tak významě pomalé že by se ten BLOB nevyplatil, a raději použít INT, který zabírá na linuxu 8 bytů?
nightfish
Profil
tester:
Napadlo mě proč se dává do tabulky uživatelů heslo typu varchar(32). Proč ne text? Ušetřilo by se místo.
Čím přesně by se ušetřilo místo? V manuálu k mySQL se píše, že pro uložení:
- varcharu do délky 255 znaků potřebuješ L + 1 bajtů (L = délka skutečně uloženého řetězce), při delším řetězci L + 2 bajtů
- sloupce typu TEXT potřebuješ L + 2 bajtů
(takže pro VARCHAR(32) ušetříš oproti TEXTu jeden bajt)

Podotázka týkající se BLOBu. Zajímalo by mě jestli je možné vytvořit číselný typ o velikosti 1 byte.
Odpovědí je datový typ TINYINT
tester
Profil *
Aha, já se domníval že délka varcharu(32) je 32 bytů. Navíc chci adresy zkracovat tím způsobem že pokud tam je nějaká ze častých domén jako seznam.cz, email.cz, gmail.com apod, tak bych tam místo zavináče dal znak identifikující doménu tím pádem to bude ještě kratší.
Keeehi
Profil
tester:
Aha, já se domníval že délka varcharu(32) je 32 bytů.
To má char(32). To var ve varcharu bude nejspíše od variable => řetězes s proměnlivou délkou.

chci adresy zkracovat
Velmi pravděpodobně naprosto zbytečná věc. Co ušetříš na datech, to ti zase přidá kód na zkracování a zpětnou rekonstrukci. Určitě nebudeš pracovat s objemy kde by každý bajt hrál význam.
Joker
Profil
tester:
Hned na začátek: Připadá mi, že řešíte neexistující problém.
Resp. se tomu říká „předčasná optimalizace“.
Různé obskurní úpravy a hacky bych dělal až ve chvíli, kdy reálně narazím na konkrétní problém, nejde ho řešit nějak „čistě“ a hlavně mám ověřené, že ten hack to vyřeší.

Protože je celkem běžné, že podobné „zlepšováky“ mají nejen hromadu nevýhod, ale ještě navíc jsou oproti standardnímu řešení horší i v tom, co měly údajně zlepšit.
(Údajný „hack na zrychlení“ je pomalejší, než standardní řešení, „hack na úsporu místa“ zabere víc místa, atd. A vůbec nejlepší je, když se nějaký amatér začne vytvářet „víc náhodný generátor náhodných čísel“, „bezpečnější kryptografické funkce“, apod.)

Napadlo mě proč se dává do tabulky uživatelů heslo typu varchar(32). Proč ne text? Ušetřilo by se místo.
Neušetřilo, viz výše.
Ale ještě doplním, že já to vidím přesně obráceně. Pokud to je pole pro heslo uživatele, určitě tam nebude heslo, ale hash, nejspíš s pevnou délkou, tj. těch 32 znaků.

A naopak by se místo ušetřilo použitím CHAR(32). S typem TEXT heslo zabere 34 bajtů, s VARCHAR 33 bajtů, s CHAR(32) 32 bajtů.

S tím právě souvisí má myšlenka zda by se BLOB(1) (1 byte) dal použít na SQLite k tomu abych neplýtval místem když potřebuju zapsat hodnotu v rozsahu 0-255.
BLOB(1) zabere 3 bajty, takže místo opravdu neušetří.

Ještě k původnímu dotazu:
Rozdíl mezi typem VARCHAR a TEXT
Co já vím, rozdíl je v tom, že VARCHAR se ukládá přímo jako součást záznamu, zatímco TEXT se ukládá mimo a v záznamu je jen nějaký ukazatel.
Takže na jedné straně není typ TEXT oproti VARCHAR omezený maximální velikostí jednoho záznamu, ale zase zabírá o 1B víc místa a práce s ním je pomalejší.

Navíc chci adresy zkracovat tím způsobem že pokud tam je nějaká ze častých domén jako seznam.cz, email.cz, gmail.com apod, tak bych tam místo zavináče dal znak identifikující doménu tím pádem to bude ještě kratší.
Vyrobí to spoustu problémů a reálný přínos bude minimální.
To už by bylo lepší vyrobit zvláštní tabulku pro domény a adresu skladovat jako uživatelské jméno a identifikátor domény (a adresa by se skládala z uživatelského jména, @ a domény získané přes JOIN z té tabulky).
Ale moc smyslu v tom nevidím, kromě toho, že by se snadno dělaly dotazy typu nejpoužívanější domény v e-mailech uživatelů.
MartinP_
Profil *
Hlavní rozdíl mezi VARCHAR a TEXT je ten, že obsah TEXTu se ukládá bokem mimo tabulku a do dat tabulky se zapíše jen odkaz. To nepatrně zpomalí prohledávání tabulky (SELECT apod.), protože se musí načítat ještě z toho vedlejšího úložiště.

To zpomalení je ale tak nepatrné, že já osobně toto neřeším a všude nastrkám TEXTy, abych nemusel řešit maximální délku. Také se nemá cenu honit za každým bajtem, databáze jsou relativně datově úsporné a sotva se s běžnými stránkami dostaneš na několik MB.
tester
Profil *
MartinP:
Tak to by mě zajímalo jak programátoři mysql vyřešili situaci, kdy uživatel změní data VARCHAR nebo TEXT. Tím že se změní délka mu nemůžeš najednou přidělit více diskové paměti to bys musel celou tabulku vygenerovat znova a přejmenovat.
Martin2
Profil *
tester:
…to bys musel celou tabulku vygenerovat znova a přejmenovat.
Až budeš navrhovat vlastní DBMS, tak dej vědět. Abychom se mu vyhnuli.

Datová struktura se negeneruje znova při každém zápisu. VARCHAR, který překročí vymezený diskový prostor, se zkrátí a doplní ukazatelem na zbylý fragment. Taky smazané řádky se nemažou, ale znovu používají. V závislosti na míře fragmentace pak DBMS tabulky jednou za čas defragmentuje. Nebo to jde udělat i ručně dotazem OPTIMIZE TABLE.
tester
Profil *
Martin2:
no to jsem si myslel, že smazané řádky se používají znova a je tam někde indexovací tabulka nebo jak se tomu říká která monitoruje ty volné řádky. Ale s tím VARCHARem nebo TEXTEM jsem to nechápal.

Jestli to teda už chápu: nastavím např. dva typy na VARCHAR(32) a TEXT(4000). Vložím do fora příspěvek dlouhý 4000 znaků a skrytý komentář o délce 32 znaků. Za nějakou dobu uživatel zedituje inzerát na délku 2000 znaků a skrytý komentář se zkrátí na 16 znaků. Posunou se ukazatelé které označují konec záznamu. Tady problém není.

Druhá situace - ta mi právě není stále jasná jak ji vyřešit.
Nastavím typ TEXT. Vložím do fora příspěvek dlouhý 256 znaků, po chvíli ho ale zedituji nebo k němu připošlu další text a délka se prodlouží na 1000. Pak přidám další text a prodlouží se na 2000. Po chvíli přidám další text, atd. až to skončí na 4000 znacích. Někdepřece musí být limit jam až mohu ten ukazatel posunout abych nenarazil na další záznam. Řešením by bylo nastavit maximum např. na 2500 znaků , přičemž si nechám rezervu na další ukazatel, který bude ukazovat na jiné místo na disku pokud budu chtít překročit vymezený limit 2500 znaků. Ale tím by vznikala právě ta fragmentace a zní mi to dost složitě. Nicméně řešitelné.


Nechci však aby každý příspěvek zabíral o +2500 bytů navíc i když je v něm jen jedno slovo, takže bych si musel stanovit nějakou rozumnou délku pro minimální text a tím by podle té mé logiky i obyčejný příspěvek s jedním slovem mohl zabírat zbytečně navíc třeba +100 bytů. Špatná logika?
Keeehi
Profil
tester:
Ale tím by vznikala právě ta fragmentace a zní mi to dost složitě.
Ale tak to taky je. Tedy alespoň přibližně. Ona si to každá databáze řeší trochu jinak. Navíc databáze se potýkají se složitějšími výzvami. A proto je taky nevytvoří jeden tester za víkend ale pracují na nich týmy odborníků i celá desetiletí.
MSTRmt
Profil
Myslím, že typ TEXT má délku stejnou jako maximální hodnota, VARCHAR je dlouhý jen jako je dlouhý text v něm.
Martin2
Profil *
tester:
Druhá situace - ta mi právě není stále jasná jak ji vyřešit.
Nechme stranou TEXT a BLOB, ten v hlavní tabulce vůbec data nemá (jen ukazatele). Co se MyISAM tabulek týče, VARCHAR nemá žádné nadbytečné místo (jen to co mohlo zůstat po jeho zkracujícím update). U prodlužujícího updatu se vytváří fragmenty. I samotný fragment pak může končit ukazatelem na další fragment. Je to stejně jako u filesystemu na disku.

Jiné databáze to pak můžou řešit jinak. Například InnoDB tabulky stránkuje, takže i záznamy s dynamickou délkou, jako je VARCHAR, mají nějaký prostor vyhrazený navíc.
rafej
Profil
Největší rozdíl VARCHAR vs TEXT v nových verzích MySQL je asi využití indexů a rychlejší dotazy u VARCHARu.

Zkus si nějaké složitější OUTER JOINy přes víc než 2 tabulky, přidej třídění či poddotazy a pak ty rozdíly v rychlosti poznáš.

Jinak vlastní uložení hodnot v řádku se dá nastavit různě. Záleží na formátu řádku i použitém enginu.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: