it-swarm-eu.dev

Jaký je dopad výkonu při používání CHAR vs. VARCHAR na pole s pevnou velikostí?

Mám indexovaný sloupec, který ukládá hash MD5. Sloupec tak bude vždy ukládat 32 znakovou hodnotu. Z jakéhokoli důvodu to bylo vytvořeno spíše jako varchar než char. Stojí za to problém s migrací databáze a její převedení na znak? Toto je v MySQL 5.0 s InnoDB.

60
Jason Baker

Podobná otázka byla položena již dříve

Výkonnostní důsledky velikostí MySQL VARCHAR

Zde je výňatek z mé odpovědi

Musíte si uvědomit kompromisy při používání CHAR vs. VARCHAR

U polí CHAR přidělujete přesně to, co získáte. Například CHAR (15) přiděluje a ukládá 15 bajtů, bez ohledu na to, jak znaky umístíte do pole. Manipulace s řetězci je jednoduchá a přímá, protože velikost datového pole je zcela předvídatelná.

S poli VARCHAR získáte úplně jiný příběh. Například VARCHAR (15) ve skutečnosti dynamicky alokuje až 16 bajtů, až 15 pro data a alespoň 1 další bajt pro uložení délky dat. Pokud máte k uložení řetězec „ahoj“, který zabere 6 bajtů, ne 5. Manipulace s řetězci musí vždy provést nějakou formu kontroly délky ve všech případech.

Kompromis je patrnější, když uděláte dvě věci: 1. Ukládání milionů nebo miliard řádků 2. Indexování sloupců, které jsou buď CHAR nebo VARCHAR

TRADEOFF # 1 Je zřejmé, že VARCHAR má výhodu, protože data s proměnnou délkou by produkovala menší řádky, a tedy menší fyzické soubory.

TRADEOFF # 2 Protože pole CHAR vyžadují menší manipulaci s řetězci kvůli pevné šířce pole, vyhledávání indexů proti poli CHAR je v průměru o 20% rychlejší než u polí VARCHAR. To není moje domněnka. Kniha MySQL Database Design and Tuning provedla na stole MyISAM něco úžasného, ​​aby to dokázala. Příklad v knize udělal něco jako následující:

ALTER TABLE tblname ROW_FORMAT=FIXED;

Tato směrnice nutí všechny VARCHARy, aby se chovaly jako CHARs. Udělal jsem to na své předchozí práci v roce 2007, vzal jsem 300GB stůl a zrychlil vyhledávání indexů o 20%, aniž bych nic jiného změnil. Fungovalo to, jak bylo publikováno. Vytvořil však tabulku téměř dvojnásobnou, ale to prostě jde zpět k kompromisu č. 1.

Mohli byste analyzovat uložená data a zjistit, co MySQL doporučuje pro definici sloupců. Stačí spustit proti každé tabulce následující:

SELECT * FROM tblname PROCEDURE ANALYSE();

Tím projdete celou tabulku a doporučíte definice sloupců pro každý sloupec na základě dat, která obsahuje, minimálních hodnot polí, maximálních hodnot polí atd. Někdy stačí při plánování CHAR vs. VARCHAR používat zdravý rozum. Zde je dobrý příklad:

Pokud ukládáte adresy IP, maska ​​pro takový sloupec je nejvýše 15 znaků (xxx.xxx.xxx.xxx). Skočil bych přímo na CHAR(15) v srdečním rytmu, protože délky IP adres se příliš nemění a přidaná složitost manipulace s řetězci řízená dalším bajtem. Proti takovému sloupci byste stále mohli udělat PROCEDURE ANALYSE(). Může dokonce doporučit VARCHAR. Moje peníze by v tomto případě stále byly na CHAR oproti VARCHAR.

Problémy CHAR vs. VARCHAR lze vyřešit pouze řádným plánováním. S velkou mocí přichází velká zodpovědnost (klišé, ale pravda).

AKTUALIZACE

Pokud jde o MD5, výpočet strlen interně by měl být vyloučen při přepínání celého formátu řádku. Není nutné měnit definici pole.

Pokud je klíč MD5 jediným přítomným VARCHARem, , půjdu za něj a převedu formát řádků tabulky na pevný . Pokud existuje významný počet dalších polí VARCHAR, byla by také přínosná. Výměnou by se tabulka rozšířila na zhruba dvojnásobek své velikosti. Dotazy by však měly zrychlit o 20% více bez dalšího ladění.

57
RolandoMySQLDBA

Vypadá to, že ušetříte 1 bajt na hodnot nebo asi 3% převodem na char. Pravděpodobně to nestojí za to, pokud skladujete MD5 v hexu stejně - můžete ušetřit 50% pomocí binary místo toho.

Díky Ovais (viz komentáře) za zdůraznění, že char(32) může použijte mnohem více než 32 bajtů , pokud používáte vícebajtovou znakovou sadu.

Děkujeme Ricku Jamesovi za to, že byste měli použít funkci unhex k převodu hexadecimálního řetězce na binární:

create table foo(bar varbinary(100));
insert into foo(bar) values(md5('a')); 
insert into foo(bar) values(unhex(md5('a'))); 
select length(bar) from foo;
 | délka (bar) | 
 | ----------: | 
 | 32 | 
 | 16 | 

db <> housle zde

Podle mého názoru se nestojí za to změnit. Pokud se podíváte do dokumentace zde, mělo by to ilustrovat rozdíl mezi nimi. Ve vašem scénáři použití ten ve skutečnosti nenabízí žádný významný přínos oproti druhému, pokud nemáte opravdu obavy z nadbytečné režie související s velikostí řádku.

http://dev.mysql.com/doc/refman/5.0/en/char.html

Také si všimněte prvního komentáře k dokumentaci, na kterou odkazuji výše ... "CHAR urychlí váš přístup, pouze pokud je celý záznam v pevné velikosti. To znamená, že pokud použijete jakýkoli objekt s proměnnou velikostí, můžete je také vytvořit všechny proměnná velikost. Nezískáte žádnou rychlost pomocí CHAR v tabulce, která také obsahuje VARCHAR "

15
RThomas