Tüm değerlerim sabit genişlikteyse CHAR'ın önerildiğini anlıyorum. Ama ne olmuş yani? Neden sadece güvende olmak için tüm metin alanları için VARCHAR'ı seçmiyoruz?
Tüm değerlerim sabit genişlikteyse CHAR'ın önerildiğini anlıyorum. Ama ne olmuş yani? Neden sadece güvende olmak için tüm metin alanları için VARCHAR'ı seçmiyoruz?
Yanıtlar:
Genellikle tüm satırlar aynı uzunluğa yakınsa CHAR seçimini yapın . Seçim VARCHAR zaman uzunluğu değişkendir önemli. CHAR da tüm satırlar aynı uzunlukta olduğundan biraz daha hızlı olabilir.
DB uygulamasına göre değişir, ancak genellikle VARCHAR gerçek verilere ek olarak bir veya iki bayt daha fazla depolama alanı (uzunluk veya sonlandırma için) kullanır. Yani (bir baytlık karakter seti kullandığınızı varsayarak) "FooBar" kelimesini saklamak
Alt satır CHAR nispeten aynı uzunlukta (iki karakter uzunluk farkı içinde) veriler için daha hızlı ve daha fazla yer verimli olabilir .
Not : Microsoft SQL'in VARCHAR için 2 bayt ek yükü vardır. Bu, DB'den DB'ye değişebilir, ancak genellikle bir VARCHAR'da uzunluğu veya EOL'yi belirtmek için en az 1 bayt ek yük gerekir.
Gaven tarafından yorumlarda belirtildiği gibi, UTF8 gibi çok baytlı, değişken uzunluklu bir karakter seti kullanıyorsanız, CHAR, karakter sayısını saklamak için gereken maksimum bayt sayısını saklar. UTF8'in bir karakteri saklamak için en fazla 3 bayta ihtiyacı varsa, CHAR (6) yalnızca latin1 karakterleri saklasa bile 18 bayta sabitlenecektir. Bu durumda VARCHAR çok daha iyi bir seçim haline gelir.
Benimle çalışıyorsanız ve Oracle ile çalışıyorsanız, muhtemelen varchar
neredeyse her koşulda sizi kullanırım . Daha char
az işlem gücü kullanan varsayım varchar
doğru olabilir ... şimdilik ... ama veritabanı motorları zamanla daha iyi hale geliyor ve bu tür genel kural gelecekteki bir "efsane" yaratıyor.
Başka bir şey: Bir performans problemi hiç görmedim çünkü biri gitmeye karar verdi varchar
. İyi kod (veritabanına daha az çağrı) ve verimli SQL (dizinler nasıl çalışır, optimize edici nasıl karar verir, neden genellikle exists
daha hızlıdır in
) yazarak zamanınızı çok daha iyi kullanacaksınız .
Son düşünce: Kullanımıyla ilgili her türlü sorunu gördüm CHAR
, '' aramaları gerektiğinde '' arayan insanlar '' veya 'FOO (burada bir sürü boşluk)' aramaları gerektiğinde 'FOO' arayan insanlar gördüm. veya sondaki boşlukları kırpmayan kişiler veya bir Oracle yordamından döndürdüğü değere 2000'e kadar boşluk ekleyen Powerbuilder'lı hatalar.
Performans avantajlarına ek olarak CHAR
, tüm değerlerin aynı uzunlukta olması gerektiğini göstermek için kullanılabilir , örneğin ABD eyalet kısaltmaları için bir sütun.
CHAR
, kısıtlama dolgusu emin olun gerekir.
Char biraz daha hızlıdır, bu yüzden BİLİNECİĞİNİZ belli bir uzunlukta olacağınız bir sütun varsa, char kullanın. Örneğin, cinsiyet için bilinmeyen (M) ale / (F) emale / (U) veya bir ABD eyaleti için 2 karakter depolamak.
NChar veya Char, var olan alternatiflerinden daha iyi performans gösteriyor mu?
Harika bir soru. Basit cevap bazı durumlarda evettir. Bakalım bu açıklanabilir mi?
Açıkçası hepimiz biliyoruz ki, bir varchar (255) sütunuyla bir tablo oluşturursam (bu sütunu myColumn olarak adlandırabiliriz) ve bir milyon satır eklerim, ancak her satır için myColumn'a sadece birkaç karakter koyarsak, tablonun çok daha küçük olacağını (genel olarak depolama motoru tarafından ihtiyaç duyulan veri sayfalarının sayısı) char (255) olarak myColumn'u oluşturduğumdan daha fazla. Ne zaman o tablo üzerinde bir işlem (DML) yapmak ve satır bir sürü talep, myColumn varchar olduğunda daha hızlı olacaktır çünkü sonunda tüm bu "ekstra" alanlarda hareket etmek zorunda değilsiniz . SQL Server'ın farklı veya birleşim işlemi gibi dahili türler yaptığı veya sorgu planı sırasında bir birleştirme seçtiği gibi olduğu gibi taşıyın.
Ancak varchar kullanımında bazı ek yükler var. SQL Server, her satırda, belirli bir satırın myColumn'unda kaç bayt olduğunu bilmek için iki baytlık bir gösterge (ek yük) kullanmalıdır. Sorunu sunan fazladan 2 bayt değil, her satırda myColumn'daki verilerin uzunluğunu "çözmek" zorunda.
Deneyimlerime göre, sorgularda birleştirilecek sütunlarda varchar yerine char kullanmak en mantıklı. Örneğin, tablonun birincil anahtarı veya dizine eklenecek başka bir sütun. Demografik tabloda CustomerNumber veya kod çözme tablosunda CodeID veya sipariş tablosunda belki OrderNumber. Char kullanarak, sorgu motoru sayfaları daha hızlı bir şekilde bayt taşımak yerine işaretçileri taşımak zorunda değilken düz pointer aritmetik (deterministik olarak) yapabileceği için birleştirme işlemini daha hızlı gerçekleştirebilir. Seni son cümle yüzünden kaybetmiş olabilirim. SQL Server'daki birleşimler "tahminler" fikrine dayanır. Bir yüklem bir durumdur. Örneğin, myColumn = 1 veya OrderNumber <500.
SQL Server bir DML deyimi gerçekleştiriyorsa ve birleştirilen tahminler veya "anahtarlar" sabit bir uzunluk (char) ise, sorgu motorunun bir tablodan satırlara eşleştirmek için çok fazla iş yapması gerekmez. başka bir tablo. Verilerin satırda ne kadar süre kaldığını bulup sonunu bulmak için dizeden aşağı inmek zorunda kalmayacak. Tüm bunlar zaman alır.
Şimdi bunun kolayca kötü bir şekilde uygulanabileceğini unutmayın. Çevrimiçi sistemlerde birincil anahtar alanlar için kullanılan char gördüm. Genişlik küçük tutulmalıdır, yani char (15) veya makul bir şey. Çevrimiçi sistemlerde en iyi sonucu verir, çünkü genellikle yalnızca az sayıda satırı alır veya üzeresiniz, bu nedenle sonuç kümesinde alacağınız sondaki boşlukları "rtrim" etmek, milyonlarca gruba katılmak yerine önemsiz bir görevdir. bir tablodan başka bir tablodaki milyonlarca satıra kadar sıralar.
CHAR'ın çevrimiçi sistemlerde varchar üzerinde anlamlı olmasının bir başka nedeni de sayfa bölünmelerini azaltmasıdır. Char kullanarak, aslında bu alanı "ayırır" (ve israf), böylece bir kullanıcı daha sonra gelir ve bu sütuna daha fazla veri koyarsa SQL zaten onun için boşluk ayırdı ve gidiyor.
CHAR'ı kullanmanın bir başka nedeni de ikinci nedene benzer. Bir programcı veya kullanıcı, örneğin bir not alanına bir cümle ekleyerek milyonlarca satıra "toplu" bir güncelleme yaparsa, gece yarısı DBA'nızdan sürücülerinin neden dolu olduğunu merak eden bir çağrı almayacaksınız. Başka bir deyişle, bir veritabanı boyutunun daha öngörülebilir büyümesine yol açar.
Yani bunlar bir çevrimiçi (OLTP) sisteminin varchar üzerinden chartan yararlanabilmesinin 3 yoludur. Ben genellikle bir depo / analiz / OLAP senaryosunda char kullanıyorum çünkü genellikle tüm bu sütunların çok fazla boşa alan ekleyebileceği çok fazla veri var.
Char'ın veritabanınızı çok daha büyük hale getirebileceğini, ancak çoğu yedekleme aracının veri sıkıştırma özelliğine sahip olduğunu, bu nedenle yedeklemelerinizin varchar kullanmış olduğunuzla aynı boyutta olma eğiliminde olduğunu unutmayın. Örneğin LiteSpeed veya RedGate SQL Yedekleme.
Başka bir kullanım, verileri sabit genişlikli bir dosyaya aktarmak için oluşturulan görünümlerdir. Diyelim ki bir ana bilgisayar tarafından okunmak için bazı verileri düz bir dosyaya vermeliyim. Sabit genişliktedir (sınırlandırılmamıştır). Verileri "aşamalandırma" tablomda varchar (böylece veritabanımda daha az yer kaplar) depolamak ve daha sonra bu sütun için sabit genişlik genişliğine karşılık gelen uzunluğu ile eşdeğer her şeyi CAST için bir görünüm kullanmak istiyorum . Örneğin:
create table tblStagingTable (
pkID BIGINT (IDENTITY,1,1),
CustomerFirstName varchar(30),
CustomerLastName varchar(30),
CustomerCityStateZip varchar(100),
CustomerCurrentBalance money )
insert into tblStagingTable
(CustomerFirstName,CustomerLastName, CustomerCityStateZip) ('Joe','Blow','123 Main St Washington, MD 12345', 123.45)
create view vwStagingTable AS
SELECT CustomerFirstName = CAST(CustomerFirstName as CHAR(30)),
CustomerLastName = CAST(CustomerLastName as CHAR(30)),
CustomerCityStateZip = CAST(CustomerCityStateZip as CHAR(100)),
CustomerCurrentBalance = CAST(CAST(CustomerCurrentBalance as NUMERIC(9,2)) AS CHAR(10))
SELECT * from vwStagingTable
Bu harika çünkü verilerim dahili olarak daha az yer kaplıyor çünkü varchar kullanıyor. Ancak DTS veya SSIS kullandığımda, hatta SSMS'den Not Defteri'ne yalnızca bir kesip yapıştırdığımda, görünümü kullanabilir ve doğru sayıda arka boşluk elde edebilirim. DTS'de eskiden bir özelliğimiz vardı, lanet olsun ki "sütunları öner" ya da başka bir şey olduğunu düşünüyorum. SSIS'de artık bunu yapamazsınız, düz dosya bağlantı yöneticisini sıkıcı bir şekilde tanımlamanız gerekir. Ancak görünüm ayarlarınızı yaptığınızdan, SSIS her bir sütunun genişliğini bilebilir ve veri akışı görevlerinizi oluştururken çok zaman kazandırabilir.
Sonuç olarak ... varchar kullanın. Char'ı kullanmak için çok az sayıda neden vardır ve bu yalnızca performans nedenleriyle ortaya çıkar. Milyonlarca satır hundrends'lı bir sisteminiz varsa, tahminler deterministik (char) ise, ancak char kullanan çoğu sistem için sadece alan israf ediyorsa fark edilir bir fark göreceksiniz.
Umarım yardımcı olur. Jeff
Performans avantajları var, ancak burada belirtilmeyen bir fayda var: satır göçü. Char ile tüm alanı önceden ayırırsınız. Diyelim ki bir karakteriniz var (1000) ve 10 karakter saklıyorsunuz, 1000 karakter alanınızı kullanacaksınız. Bir varchar2'de (1000) yalnızca 10 karakter kullanırsınız. Verileri değiştirdiğinizde sorun ortaya çıkar. Sütunu şimdi 900 karakter içerecek şekilde güncellediğinizi varsayalım. Varchar'ı genişletecek alanın mevcut blokta mevcut olmaması mümkündür. Bu durumda, DB motoru satırı başka bir bloğa geçirmeli ve orijinal blokta yeni bloktaki yeni satıra bir işaretçi yapmalıdır. Bu verileri okumak için, DB motorunun şimdi 2 bloğu okuması gerekecektir.
Hiç kimse varchar veya char'ın daha iyi olduğunu açıkça söyleyemez. Zaman aşımı için bir alan vardır ve özellikle de büyümesi için iyi bir şans varsa, verilerin güncellenip güncellenmeyeceğini düşünün.
Erken performans optimizasyonu ile en iyi uygulama kuralı kullanmak arasında bir fark vardır. Her zaman sabit uzunluklu bir alana sahip olacağınız yeni tablolar oluşturuyorsanız, CHAR kullanmak mantıklıdır, bu durumda kullanmalısınız. Bu erken optimizasyon değil, daha çok bir kural (veya en iyi uygulama) uygulamak.
ie - 2 harfli durum alanınız varsa, CHAR (2) kullanın. Gerçek durum adlarına sahip bir alanınız varsa, VARCHAR'ı kullanın.
Sütun her zaman 2 karakter uzunluğunda ve geçerli ABD devletleri kodu listesi sık sık değişmez :) ABD devlet kodu gibi sabit bir değer depolamak sürece varchar seçerim :).
Diğer her durumda, karma parolayı (sabit uzunluklu) depolamak gibi, varchar'ı seçerdim.
Neden - char tipi sütun her zaman boşluklarla yerine getirilir; bu, karşılaştırma içinde 'ABC' değeriyle char (5) olarak tanımlanan my_column sütununu yapar :
my_column = 'ABC' -- my_column stores 'ABC ' value which is different then 'ABC'
yanlış.
Bu özellik geliştirme sırasında birçok rahatsız edici hataya neden olabilir ve testi zorlaştırır.
Bu alandaki tüm veri değerleriniz aynı uzunlukta ise CHAR, VARCHAR'dan daha az depolama alanı kaplar. Şimdi belki de 2009'da 800GB veritabanı tüm hedefler ve amaçlar için aynıdır, eğer VARCHAR'ları CHAR'lara dönüştürdüyseniz, ancak kısa dizeler (1 veya 2 karakter) için CHAR hala bir endüstri "en iyi uygulaması" diyorum.
Şimdi, çoğu veritabanının yalnızca tamsayılar (bit, tiny, int, bigint) için bile sağladığı çok çeşitli veri türlerine bakarsanız, birini diğerinden seçmek için nedenler vardır. Her seferinde bigint'i seçmek aslında alanın amaçlarından ve kullanımlarından biraz habersizdir. Bir tarla sadece yaşları olan bir kişiyi temsil ediyorsa, bigint aşırıya kaçar. Şimdi mutlaka "yanlış" değil, ama etkili değil.
Ancak bu ilginç bir argüman ve veritabanları zaman içinde geliştikçe CHAR vs VARCHAR'ın daha az alakalı hale geldiği iddia edilebilir.
Jim McKeeth'in yorumunun yanındayım.
Ayrıca, tablonuzda yalnızca CHAR sütunları varsa dizin oluşturma ve tam tablo taramaları daha hızlıdır. Temel olarak optimizer, her bir kaydın yalnızca CHAR sütunları varsa ne kadar büyük olduğunu tahmin edebilecekken, her VARCHAR sütununun boyut değerini kontrol etmesi gerekir.
Ayrıca, bir VARCHAR sütununu önceki içeriğinden daha büyük bir boyuta güncellerseniz, veritabanını dizinlerini yeniden oluşturmaya zorlayabilirsiniz (çünkü veritabanını diskteki kaydı fiziksel olarak taşımak zorunda kaldınız). CHAR sütunları ile asla olmayacak.
Ancak, tablonuz büyük olmadıkça muhtemelen performans isabetini umursamazsınız.
Djikstra'nın akıllı sözlerini hatırla. Erken performans optimizasyonu tüm kötülüklerin köküdür.
CHAR
sütunu güncellediğinizde , dizinlerin de güncellenmesi gerekir. Bu bağlamda bir VARCHAR veya CHAR sütununu güncellemede bir fark yoktur. Güncellenmesi düşünün FOO
için BAR
.
Birçok kişi, CHAR kullanarak değerin tam uzunluğunu biliyorsanız bazı faydalara sahip olduğuna dikkat çekmiştir. Ancak ABD eyaletlerini CHAR (2) olarak depolamak bugün harika olsa da, satışlardan 'Avustralya'ya ilk satışımızı yaptık' mesajını aldığınızda, acı dünyasındasınız. Gelecekteki olayları kapsamak için 'kesin' bir tahmin yapmak yerine alanların ne kadar süreceğini düşündüğümü her zaman tahmin etmek için gönderirim. VARCHAR bana bu alanda daha fazla esneklik sağlayacak.
Sanırım senin durumunda Varchar'ı seçmemek için hiçbir sebep yok. Size esneklik sağlar ve bir dizi katılımcı tarafından belirtildiği gibi, performans şimdi çok spesifik koşullar dışında (Google DBA'ların aksine) daha fazla fark yaratmayacak.
DB Türleri söz konusu olduğunda dikkat çeken ilginç bir şey, sqlite (oldukça etkileyici performansa sahip popüler bir mini veritabanı) her şeyi veritabanına bir dize ve türler olarak koyar.
Her zaman VarChar kullanıyorum ve genellikle ihtiyacım olandan çok daha büyük yapıyorum. Örneğin. 50 Neden First Name için, neden sadece güvenli olmak değil.
ASLA karakter kullanmam. Birçok insanla bu tartışmayı yaşadım ve her zaman char'ın daha hızlı olduğu yorgun klişeyi ortaya çıkarırlar. Peki, ne kadar hızlı? Burada neden bahsediyoruz, milisaniye, saniye ve eğer öyleyse kaç tane? Bana söylüyorsun çünkü birisi birkaç milisaniyeden daha hızlı olduğunu iddia ediyor, sisteme tonlarca düzeltilmesi zor hatalar getirmeliyiz?
İşte size karşılaşacağınız bazı sorunlar:
Her alan dolgulu olacak, böylece sonsuza kadar her yerde RTRIMS olan bir kodla karşılaşacaksınız. Bu aynı zamanda uzun alanlar için büyük bir disk alanı israfıdır.
Şimdi diyelim ki sadece bir karakterlik bir char alanının özlü bir örneğine sahipsiniz ancak alan isteğe bağlıdır. Birisi bu alana boş bir dize geçirirse, bir boşluk haline gelir. Başka bir uygulama / işlem sorguladığında, rtrim kullanmazlarsa tek bir alan alırlar. İsteğe bağlı alanlarda xml dokümanlarımız, dosyalarımız ve diğer programlarımız var, yalnızca bir alan gösterdik ve bir şeyler kırdık.
Bu yüzden şimdi boş alana değil, boş karakterleri char alanına geçirdiğinizden emin olmalısınız. Ancak bu null değerinin doğru kullanımı DEĞİLDİR. İşte null kullanımı. Diyelim ki bir satıcıdan dosya alıyorsunuz
Ad | Cinsiyet | Şehir
Bob || Los Angeles
Bob girdiğinizden cinsiyet belirtilmezse, tabloya boş dize ve Los Angeles yazın. Şimdi dosyayı alacağınızı ve dosya biçiminin değiştiğini ve cinsiyetin artık dahil olmadığını ancak geçmişte olduğunu varsayalım.
Ad | Şehir
Bob | Seattle
Şimdi cinsiyet dahil olmadığından, null kullanacağım. Varchars bunu sorunsuz bir şekilde desteklemektedir.
Öte yandan Char farklıdır. Her zaman null göndermeniz gerekir. Hiç boş dize gönderirseniz, içinde boşluk bulunan bir alanla karşılaşırsınız.
Ben chars ve yaklaşık 20 yıllık gelişme düzeltmek zorunda kaldım tüm hatalar ile devam ve devam.
Bir sütun değeri için gereken gerçek boyutun hesaplanmasında ve bir Varchar için alan tahsis edilmesinde küçük bir işlem yükü vardır, bu nedenle değerin her zaman ne kadar uzun olacağından kesinlikle eminseniz, Char'ı kullanmak ve isabetten kaçınmak daha iyidir.
Performans dengesine karşı klasik alan.
MS SQL 2005'te Varchar (veya karakter başına iki bayt, yani Çince için gereken baytlar için NVarchar) değişken uzunluktadır. Sabit diske yazıldıktan sonra satıra eklerseniz, verileri orijinal satıra uygun olmayan bir konumda bulur ve veri dosyalarınızın parçalanmasına neden olur. Bu performansı etkileyecektir.
Bu yüzden, alan bir sorun değilse, Char performans için daha iyidir, ancak veritabanı boyutunu düşük tutmak istiyorsanız varchars daha iyidir.
Parçalanma. Char yer ayırır ve VarChar bunu yapmaz. Varchar güncellemesine uyum sağlamak için sayfa bölünmesi gerekebilir.
CHAR
sütun güncellenirken sayfa bölünmesi meydana gelebilir .
Bazı SQL veritabanlarında, VARCHAR ofsetleri optimize etmek için maksimum boyutuna kadar doldurulur, Bu tam tablo taramalarını ve dizinleri hızlandırmak içindir.
Bu nedenle, bir CHAR (200) ile karşılaştırıldığında bir VARCHAR (200) kullanarak yerden tasarruf edemezsiniz
CHAR (NCHAR) ve VARCHAR (NVARCHAR) kullanmak, veritabanı sunucusunun verileri depolama biçiminde farklılıklar getirir. Birincisi sondaki boşlukları tanıtır; SQL SERVER işlevlerinde LIKE operatörü ile kullanırken sorunla karşılaştım. Bu yüzden her zaman VARCHAR (NVARCHAR) kullanarak güvenli hale getirmem gerekiyor.
Örneğin, bir TEST (ID INT, Status CHAR (1)) tablonuz varsa ve aşağıdaki gibi belirli bir değere sahip tüm kayıtları listelemek için bir işlev yazarsanız:
CREATE FUNCTION List(@Status AS CHAR(1) = '')
RETURNS TABLE
AS
RETURN
SELECT * FROM TEST
WHERE Status LIKE '%' + @Status '%'
Bu işlevde, varsayılan parametreyi koyduğumuzda işlevin tüm satırları döndürmesini bekleriz, ancak aslında geri dönmez. @Status veri türünü VARCHAR olarak değiştirmek sorunu çözecektir.