Sabit boyutlu bir alanda CHAR vs VARCHAR kullanmanın performans etkisi nedir?


58

Bir MD5 karma depolayan bir dizinlenmiş sütun var. Böylece, sütun her zaman 32 karakterlik bir değeri saklar. Hangi nedenle olursa olsun, bu bir karakter değil, bir varkar olarak yaratıldı. Veritabanını bir karaktere dönüştürmek için geçirme zorluğuna değer mi? Bu InnoDB ile MySQL 5.0 içinde.


6
UYARI Bu soru ve cevapları InnoDB ve utf8 öntanımlı idi.
Rick James,

Yanıtlar:


56

Benzer bir soru daha önce de sorulmuştu.

MySQL VARCHAR boyutlarının performans etkileri

İşte cevabımın alıntı

CHAR vs VARCHAR kullanmanın değişmezliğini gerçekleştirmelisin.

CHAR alanları ile tahsis ettiğiniz tam olarak ne elde ettiğinizdir. Örneğin, CHAR (15), alana ne kadar karakter koyduğunuz önemli değil, 15 bayt ayırır ve saklar. Veri alanının boyutu tamamen tahmin edilebilir olduğundan, dize manipülasyonu basit ve kolaydır.

VARCHAR alanları ile tamamen farklı bir hikaye edinirsiniz. Örneğin VARCHAR (15) aslında veri için en fazla 16 bayt, veri için 15 ve en az 1 veri baytını depolar. Eğer saklamak için 'merhaba' dizgesi varsa, 6 bayt alacaktır, 5 değil. Dize manipülasyonu her zaman her durumda bir miktar uzunluk kontrolü yapmalıdır.

İki şeyi yaptığınızda tradeoff daha belirgindir: 1. Milyonları veya milyarlarca satırı saklamak 2. CHAR veya VARCHAR olan sütunların indekslenmesi

TRADEOFF # 1 Açıkçası VARCHAR, değişken uzunluktaki veriler daha küçük satırlar ve dolayısıyla daha küçük fiziksel dosyalar üreteceğinden avantaj sağlar.

TRADEOFF # 2 CHAR alanları sabit alan genişlikleri nedeniyle daha az string işleme gerektirdiğinden, CHAR alanına karşı indeks aramaları VARCHAR alanlarına göre ortalama% 20 daha hızlıdır. Bu benim açımdan herhangi bir varsayım değil. MySQL Veritabanı Tasarımı ve Ayarlaması kitabı bunu kanıtlamak için MyISAM masasında muhteşem bir şey yaptı. Kitaptaki örnek şöyle bir şey yaptı:

ALTER TABLE tblname ROW_FORMAT=FIXED;

Bu yönerge, tüm VARCHAR'ları CHAR'lar gibi davranmaya zorlar. Bunu 2007'deki önceki işimde yaptım ve 300 GB'lık bir masa aldım ve başka bir şeyi değiştirmeden dizin aramalarını% 20 artırdım. Yayınlandığı gibi çalıştı. Ancak, neredeyse iki katı büyüklüğünde bir masa üretti, ancak bu sadece 1 numaralı tradeoff'a geri döndü.

MySQL'in sütun tanımı için neler önerdiğini görmek için depolanan verileri analiz edebilirsiniz. Sadece aşağıdakileri herhangi bir masaya karşı çalıştırın:

SELECT * FROM tblname PROCEDURE ANALYSE();

Bu, tüm tabloyu geçecek ve içerdiği verilere, minimum alan değerlerine, maksimum alan değerlerine ve benzerlerine bağlı olarak her sütun için sütun tanımları önerecektir. Bazen, CHAR vs VARCHAR'ı planlarken sağduyunuzu kullanmanız gerekir. İşte güzel bir örnek:

IP adreslerini saklıyorsanız, böyle bir sütunun maskesi en çok 15 karakterdir (xxx.xxx.xxx.xxx). Tam bir atlayışta CHAR(15)zıplayacağım, çünkü IP adreslerinin uzunluğu o kadar fazla değişmeyecek ve ek bir bayt tarafından kontrol edilen dize manipülasyonunun karmaşıklığı da değişmeyecek. PROCEDURE ANALYSE()Böyle bir sütuna karşı hala bir şey yapabilirsin . VARCHAR'ı bile önerebilir. Bu durumda param hala VARCHAR üzerinden CHAR'da olacaktı.

CHAR-VARCHAR sorunları sadece uygun planlama ile çözülebilir. Büyük güç ile büyük sorumluluk gelir (klişe ama gerçek).

GÜNCELLEME

MD5 söz konusu strlenolduğunda, tüm satır formatı değiştirilirken dahili olarak hesaplanması elimine edilmelidir. Alan tanımını değiştirmeye gerek kalmayacaktı.

MD5 anahtarı yalnızca mevcut VARCHAR ise, bunun için gider ve tablo satır biçimini sabit hale getirirdim . Çok sayıda başka VARCHAR alanı mevcutsa, bunlar da fayda sağlar. Buna karşılık, masa, boyutunun yaklaşık iki katı kadar genişlerdi. Ancak, sorgular ilave ayar yapılmadan yaklaşık% 20 daha fazla hızlanmalıdır.


1
Bir IP adresi için bir karakter (4) veya işaretsiz bir tamsayı gibi bir şey kullanırım
Jack Douglas

@JackPDouglas Bu konuda haklısın.
RolandoMySQLDBA,

Endeksler zaten belirli bir uzunlukta saklı değil mi? Depolama formatının sabit uzunluktaki gelişmiş dizin aramalarına nasıl değiştirileceğini anlamıyorum. Gelişmiş masa taramaları mı demek istiyorsun?
Marcus Adams,

1
@ JackDouglas, Neden bitve binary?
Pacerier

Daha iyi olurdu @Pacerier, katılıyorum :)
Jack Douglas

19

Bir değere dönüştürerek değer başına 1 bayt veya yaklaşık% 3 tasarruf edeceksiniz gibi görünüyor char. Zaten MD5'i hex'te saklıyorsanız muhtemelen buna değmez - binarybunun yerine % 50 tasarruf edebilirsiniz .

Buna dikkat çektiğin için Ovais sayesinde (yorumlara bakınız) char(32)olabilir bir sürü fazla 32 bayt kullanmak çok baytlı karakter kümesi kullanıyorsanız.

Rick James'e unhexonaltılık bir dize binary dönüştürmek için işlevi kullanmanız gerektiğini belirtti için teşekkürler :

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;
| uzunluk (bar) |
| ----------: |
| 32 |
| 16 |

db <> burada keman


İkili olarak değiştirme konusunda iyi çağrı.
RThomas

Bunu bir ikiliye dönüştürmeyi planlıyorum. Şimdi düşünüyorum da, kodlamanın utf-8 olduğundan, boyutun sadece bir bayt mı yoksa bir karakter mi kullandığıma bağlı olarak farklı olmaması gerekir. Yoksa yanlış mıyım?
Jason Baker

@Jason - kodlama için geçerli değil binary- ya da yanlış mı anladım?
Jack Douglas

3
utf-8 karakter kümesine sahip bir karakter (32) sütunu için, her değer depolama için 32x3 bayta ihtiyaç duyar. MD5 karma değerini neden utf-8 olarak ayarlamanız gerekiyor? İkili dosyaya (32) dönüştürmek için değer başına 32 bayta ihtiyaç vardır.
ovais.tariq

1
BINARYSiz de kullanmıyorsanız, değiştirmek çok az şey yapar UNHEX(). Yani saklayabilir olan UNHEX(MD5(x))16-byte içine BINARY(16)saklamak üzerinde önemli yer kazanmak için MD5(x)içine CHAR(32) CHARACTER SET ascii.
Rick James,

15

Bence değişmeye değmez. Buradaki belgelere bakarsanız, ikisi arasındaki farkı göstermelidir. Kullanım senaryonuzda, satır büyüklüğü ile ilgili fazladan bir miktar fazladan endişe duymuyorsanız, biri diğerine karşı gerçekten önemli bir fayda sağlamaz.

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

Ayrıca yukarıda bağlantı verdiğim belgelere ilişkin ilk yorumu not edin ... "CHAR yalnızca tüm kaydın sabit olması durumunda erişiminizi hızlandıracaktır. Yani, eğer değişken boyutta bir nesne kullanırsanız, hepsini de yapabilirsiniz. VARCHAR "içeren bir tabloda CHAR kullanarak hız kazanmazsınız"


Bu "hız", InnoDB için değil, MyISAM için geçerlidir.
Rick James,
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.