Tüm metin tabanlı alanlar için genel bir varchar (255) kullanmanın dezavantajları var mı?


100

Ben var contactsgibi alanları içeren tabloyu postcode, first name, last name, town, country, phone numbervb olarak tanımlanan hepsi VARCHAR(255)hatta bu alanların hiçbiri yakın 255 karakteri haiz gelecek olsa. (Merak ediyorsanız, bu böyledir çünkü Ruby on Rails geçişleri String alanlarını VARCHAR(255)varsayılan olarak eşler ve ben onu geçersiz kılmaktan hiç rahatsız olmadım).

VARCHAR yalnızca alanın gerçek karakterlerinin sayısını (alan uzunluğu ile birlikte) depolayacağından, kullanmanın belirgin bir avantajı (performans veya başka türlü) VARCHAR(16)var VARCHAR(255)mı?

Ek olarak, bu alanların çoğunun üzerinde indeksler vardır. Alandaki daha büyük bir VARCHAR boyutu dizinin boyutunu veya performansını hiç etkiliyor mu?

Bilginize MySQL 5 kullanıyorum.


2
@ceejayoz, neden gerçekten yardımcı olmadığını açıklamadan kabul edilen cevabın yanlış olduğunu belirterek. Daha da kötüsü, kabul edilen cevabın zamanla değişebileceği ve yorumunuzun insanların yeni kabul edilen cevabın yanlış olduğunu düşünmelerine yol açmasıdır.
Gili

1
@Gili OP görünüşe göre kabullerini değiştirdiği için yorumumu sildi. İyi noktalar, gelecekte hangi cevaptan ve neden bahsettiğimi belirteceğim.
ceejayoz

Bu yinelenen soruya bazı diğer yanıtlar, stackoverflow.com/questions/1262174/…
James McMahon

Yanıtlar:


129

Depolamada, her zaman 255 karakter depolayacağından VARCHAR(255)farklı olarak, yalnızca ihtiyacınız olan uzunluğu belirli bir satırda depolayacak kadar akıllıdır CHAR(255).

Ancak bu soruyu MySQL ile etiketlediğiniz için, MySQL'e özgü bir ipucundan bahsedeceğim: satırlar depolama motoru katmanından SQL katmanına kopyalandıkça, VARCHARalanlar CHARsabit genişlikteki satırlarla çalışmanın avantajını elde etmek için dönüştürülür . Böylece bellekteki dizeler , bildirilen sütununuzun maksimum uzunluğuna kadar doldurulurVARCHAR .

Sorgunuz örtük olarak geçici bir tablo oluşturduğunda, örneğin sıralama sırasında veya GROUP BYbu çok fazla bellek kullanabilir. VARCHAR(255)O kadar uzun olması gerekmeyen veriler için çok fazla alan kullanırsanız , bu geçici tabloyu çok büyük hale getirebilir.

Ayrıca, bu "doldurma" davranışının, utf8 karakter kümesiyle bildirilen bir dizenin, tek baytlık içerikle (örneğin, ascii veya latin1 karakterleri) sakladığınız dizeler için bile karakter başına üç bayta kadar ödeme yapacağı anlamına geldiğini bilmek isteyebilirsiniz. Ve benzer şekilde utf8mb4 karakter kümesi, dizenin bellekteki karakter başına dört bayta kadar doldurmasına neden olur.

Dolayısıyla, VARCHAR(255)"Fikrim yok" gibi kısa bir dizeyi depolayan bir utf8 içinde diskte 11 bayt alır (on alt karakter grubu artı uzunluk için bir bayt) ancak bellekte ve dolayısıyla geçici tablolarda veya sıralı sonuçlarda 765 bayt alır.

Farkında olmadan sık sık 1,5 GB geçici tablolar oluşturan ve disk alanlarını dolduran MySQL kullanıcılarına yardımcı oldum. VARCHAR(255)Pratikte çok kısa dizeler depolayan çok sayıda sütunları vardı .

En iyisi, depolamayı düşündüğünüz veri türüne göre sütunu tanımlamaktır. Diğer insanların da bahsettiği gibi, uygulama ile ilgili kısıtlamaları zorlama faydaları vardır. Ancak yukarıda anlattığım hafıza israfını önlemek için fiziksel faydaları var.

Elbette en uzun posta adresinin ne olduğunu bilmek zordur, bu yüzden birçok insan VARCHARkesinlikle herhangi bir adresten daha uzun bir uzun posta adresi seçer . 255 ise gelenekseldir çünkü VARCHARuzunluğu bir bayt ile kodlanabilen maksimum a uzunluğudur. Ayrıca VARCHARMySQL'de 5.0'dan daha eski olan maksimum uzunluktu.


6
Her zaman 255dizenin uzunluğunun tek bir bayta sığması için kullanıldığını düşünmüşümdür
BlueRaja - Danny Pflughoeft

3
@BlueRaja: Bu muhtemelen dahili dosya yapısı tek bir baytta bir dizginin uzunluğunu kodlayan veritabanları için veya kısa dizeleri tek bir baytta kodlamışlarsa doğruydu. Ancak çoğu veritabanı için artık doğru değil.
Bill Karwin

7
@BlueRaja: InnoDB, aşağıdaki varchar'ın uzunluğunu saklamaz, satırdaki tüm alanlar için bir dizi alan ofsetini depolar. Bu alan uzaklıkları, toplam satır boyutu 127 bayttan azsa 1 bayt veya 2 bayt olabilir. Bkz forge.mysql.com/wiki/MySQL_Internals_InnoDB
Bill Karwin

6
@BlueRaja: MyISAM (hala kullananlar için) varchar uzunluklarını depolar ve bunlar 1 veya 2 baytta saklanabilir. Ancak: "index_read () veya records_in_range için işleyiciye bir anahtar gönderirken, işleri daha basit hale getirmek için her zaman VARCHAR için 2 baytlık uzunluk kullanırız." Bkz forge.mysql.com/wiki/MySQL_Internals_MyISAM
Bill Karwin

1
bir soru - herhangi bir alana veya varchar alanının kendisine göre sıralama ve gruplama?
Rohit Banga

24

Bir varchar boyutunu ayarlamanın boyut ve performans değerlendirmelerine ek olarak (ve muhtemelen depolama ve işleme her saniye ucuzladıkça daha da önemlisi), varchar (255) kullanmanın dezavantajı "sadece" veri bütünlüğünün azalmasıdır .

Dizeler için maksimum sınırların tanımlanması, beklenenden daha uzun dizelerin RDBMS'ye girmesini ve daha sonra veritabanından beklenenden daha uzun (daha fazla bayt) değerler alırken ve ayrıştırırken arabellek taşmalarına veya istisnalara / hatalara neden olmasını önlemek için yapılacak iyi bir şeydir .

Örneğin, ülke kısaltmaları için iki karakterli dizileri kabul eden bir alanınız varsa, kullanıcılarınızın (bu bağlamda programcıların) tam ülke adlarını girmesini beklemek için makul bir nedeniniz yoktur. "Antigua ve Barbuda" (AG) veya "Heard Adası ve McDonald Adaları" (HM) girmelerini istemediğiniz için, veritabanı katmanında buna izin vermezsiniz. Ayrıca, bazı programcıların bunu yapmamayı bilmeleri için ( kesinlikle var olan ) tasarım belgelerini henüz RTFMed etmemiş olmaları muhtemeldir .

Alanı iki karakteri kabul edecek şekilde ayarlayın ve RDBMS'nin bununla ilgilenmesine izin verin (ya kısaltarak nazikçe ya da SQL'lerini bir hata ile reddederek dikkatsizce).

Belirli bir uzunluğu aşmak için hiçbir neden bulunmayan gerçek verilere örnekler:

  • Kanada Posta Kodları A1A1A1 biçimindedir ve Noel Baba için bile her zaman 6 karakter uzunluğundadır (okunabilirlik için belirtilebilen boşluk 6 karakter hariçtir).
  • e-posta adresleri - @ işaretinden önce en çok 64 bayt, sonra en çok 255 bayt. Asla, interneti kırarsınız diye.
  • Kuzey Amerika Telefon Numaraları asla 10 haneden fazla değildir (ülke kodu hariç).
  • Windows çalıştıran bilgisayarlar (son sürümleri) 63 bayttan uzun bilgisayar adlarına sahip olamaz , ancak 15'ten fazlası önerilmez ve Windows NT sunucu grubunuzu bozar.
  • Eyalet kısaltmaları 2 karakterdir (yukarıda örneklenen ülke kodları gibi)
  • UPS takip numaraları 18-, 12-, 11- veya 9 karakter uzunluğundadır. 18 karakterli sayılar "1Z" ile başlar ve 11 karakterli sayılar "T" ile başlar, bu da harflerle sayılar arasındaki farkı bilmiyorlarsa tüm bu paketleri nasıl teslim ettiklerini merak etmenize neden olur.

Ve bunun gibi...

Verilerinizi ve sınırlarını düşünmek için zaman ayırın. Bir mimar, geliştirici veya programcıysanız, sonuçta bu sizin işinizdir .

Varchar (255) yerine bir varchar (n) kullanarak, kullanıcıların (son kullanıcılar, programcılar, diğer programlar) daha sonra kodunuza musallat olacak beklenmedik şekilde uzun veriler girmesi sorununu ortadan kaldırırsınız .

Ve bu kısıtlamayı uygulamanız tarafından kullanılan iş mantığı koduna da uygulamamanız gerektiğini söylemedim.


5
Kanada posta kodları aslında 7 hanelidir, ortadaki boşluk önemlidir ve posta etiketlerinde gösterilmelidir. Bir uzantı varsa, Kuzey Amerika telefon numaraları 10'dan fazla haneye sahip olabilir. Telefon numarası uzantılarını saklayamamakta sorun yoksa, 10 basamak yeterlidir, ancak muhtemelen pişman olacaksınız.
Kibbee

3
Veri bütünlüğü için kesinlikle kısıtlayıcı olma durumu vardır. Yine de çok kısıtlayıcı olmak yine de kolaydır. Kontrol ettiğiniz veriler için kısıtlamalar uygulayın ve kontrol edemediğiniz veri gereksinimleri için makul kısıtlamalar uygulayın. Telefon numaranız ve e-posta kısıtlamalarınız mantıklıdır (asla uluslararası hale getirmeyeceğinizi varsayarak). İki karakterli bir ülke kodunu kesmenin "zarif" bir şey olduğunu söyleyen gereksiniminiz çılgınlıktır. Bir hata olduğunu biliyorsunuz, kısaltmayın ve kabul edin. Son derece yüksek bir olasılıkla keserseniz, yanlış bir ülke koduyla sonuçlanırsınız.
coderjoe

Çoğu uygulamada, veri tabanına gönderilmeden önce veri doğrulaması yapılacak ...
Cobby

2
Elbette. Çoğu. Ancak burada, mevcut bir veritabanı için yeni bir uygulama geliştiren bir geliştiricinin veriler üzerindeki kısıtlamaların farkında olduğunu varsaydığınızı hissediyorum (hepimiz her tür veri ve bunların her veritabanında nasıl uygulandığı konusunda uzman değiliz) ). Başvurunuzdaki verileri doğrulayabilmeniz, yaptığınız anlamına gelmez.
shufler

3
the design documentation (which surely exists)Hah. : D
Camilo Martin

14

Seninleyim. Detaylara gösterilen telaşlı dikkat, boyunda bir ağrıdır ve sınırlı bir değere sahiptir.

Bir zamanlar disk çok değerli bir üründü ve onu optimize etmek için mermi terletiyorduk. Depolamanın fiyatı 1.000 kat düştü ve her baytı sıkıştırmak için harcanan zamanı daha az değerli hale getirdi.

Yalnızca CHAR alanlarını kullanırsanız, sabit uzunlukta satırlar alabilirsiniz. Alanlar için doğru boyutları seçtiyseniz, bu bazı disk gerçek değerlerini kaydedebilir. Daha yoğun şekilde paketlenmiş veriler (tablo taramaları için daha az G / Ç) ve daha hızlı güncellemeler (güncellemeler ve eklemeler için bir bloktaki açık alanları bulmak daha kolay) elde edebilirsiniz.

Bununla birlikte, boyutlarınızı fazla tahmin ederseniz veya gerçek veri boyutlarınız değişkense, CHAR alanlarıyla yer israfına neden olursunuz. Veriler daha az yoğun bir şekilde paketlenir (büyük geri alımlar için daha fazla G / Ç'ye yol açar).

Genel olarak, değişken alanlara bir boyut koymaya çalışmanın performans faydaları küçüktür. Farkı ölçüp ölçemeyeceğinizi görmek için VARCHAR (255) ile CHAR (x) ile karşılaştırarak kolayca kıyaslama yapabilirsiniz.

Ancak bazen "küçük", "orta", "büyük" bir ipucu sağlamam gerekir. Bu yüzden bedenler için 16, 64 ve 255 kullanıyorum.


13

Bugünlerde artık önemli olduğunu hayal bile edemiyorum.

Değişken uzunluklu alanları kullanmanın bir hesaplama ek yükü vardır, ancak günümüz CPU'larının fazlalığı nedeniyle, dikkate almaya bile değmez. I / O sistemi, varchars etkin bir şekilde varolmayan bir şekilde işlemek için herhangi bir hesaplama maliyeti yapacak kadar yavaştır. Aslında, bir varchar'ın fiyatı sayısal olarak sabit uzunluklu alanlar üzerinde değişken uzunluklu alanlar kullanılarak kaydedilen disk alanı miktarına göre net bir kazançtır. Büyük olasılıkla daha fazla sıra yoğunluğuna sahipsiniz.

Şimdi, varchar alanlarının karmaşıklığı, kayıt numarası aracılığıyla bir kaydı kolayca bulamamanızdır. Sabit uzunlukta satır boyutuna sahip olduğunuzda (sabit uzunluklu alanlarla), bir satır kimliğinin işaret ettiği disk bloğunu hesaplamak önemsizdir. Değişken uzunluktaki satır boyutuyla, bu tür pencereden dışarı çıkar.

Bu nedenle, şimdi, tıpkı diğer birincil anahtarlar gibi bir tür kayıt numarası indeksi tutmanız gerekir VEYA tanımlayıcıya ayrıntıları (blok vb.) Kodlayan sağlam bir satır tanımlayıcı yapmanız gerekir. Ancak bunu yaparsanız, satır kalıcı depolamaya taşınırsa kimliğin yeniden hesaplanması gerekir. Önemli değil, sadece tüm indeks girişlerini yeniden yazmanız ve ya a) tüketiciye asla maruz bırakmadığınızdan ya da b) sayının güvenilir olduğunu asla iddia etmediğinizden emin olmanız yeterlidir.

Ancak bugün varchar alanlarımız olduğu için, varchar (16) 'nın varchar (255) üzerindeki tek değeri, DB'nin varchar (16) üzerinde 16 karakter sınırını uygulayacağıdır. DB modelinin fiilen fiziksel veri modelini temsil etmesi gerekiyorsa, alan uzunluklarına sahip olmak değerli olabilir. Bununla birlikte, bir "model VE depolama" yerine basitçe "depolama" ise, herhangi bir şeye gerek yoktur.

Ardından, dizine eklenebilen bir metin alanı (varchar gibi) ile olmayan bir şey (bir metin veya CLOB alanı gibi) arasında ayrım yapmanız gerekir. İndekslenebilir alanlar indeksi kolaylaştırmak için bir boyut sınırına sahip olma eğilimindeyken CLOB alanları (sebep dahilinde) yoktur.


5

Tecrübelerime göre, 255 karakterlik bir veri türüne izin verirseniz, bazı aptal kullanıcılar (veya bazı deneyimli testçiler) aslında bunu dolduracaktır.

Daha sonra, uygulamanızda raporlarda ve ekran görüntülerinde bu alanlar için ne kadar alan bıraktığınız da dahil olmak üzere her türlü sorununuz var. Veritabanınızdaki veriler için satır başına sınırını aşma olasılığından bahsetmiyorum bile (bu 255 karakter alanlarından birkaçından fazlasına sahipseniz).

Başlangıçta makul bir sınır seçmek çok daha kolay, ardından bunu uygulama ve veritabanı aracılığıyla uygulamak.


0

İhtiyacınız olanın sadece biraz fazlasını ayırmak iyi bir uygulamadır. Telefon numaraları asla bu kadar büyük olmaz.

Bunun bir nedeni, büyük girişlere karşı doğrulama yapmadığınız sürece, hiç şüphesiz birinin var olan her şeyi kullanacağıdır. O zaman sıranızda yer kalmayabilir. MySQL sınırından emin değilim, ancak 8060 MS SQL'deki maksimum satır boyutu.

Daha normal bir varsayılan değer 50 imho'dur ve daha sonra ihtiyacın kanıtladığı yerde artar.


Teşekkürler. Bunun iyi bir uygulama olduğuna kesinlikle katılıyorum. Açıklamak istediğim performans yönü
Olly

0

Bir mysql bağlamında, söz konusu varchar sütunlarında dizinler ile çalışırken, mysql'in maks. endeks satırı başına 767 bayt sınırı.

Bu, birkaç varchar 255 sütununa bir dizin eklerken, yukarıdaki yanıtlarda belirtildiği gibi utf8 veya utf8mb4 sütunlarında bu sınıra oldukça hızlı / daha hızlı ulaşabileceğiniz anlamına gelir.

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.