MySQL: Büyük VARCHAR mı TEXT mi?


845

MySQL'de kullanıcılar arasındaki mesajları kaydeden bir mesaj tablosu var. Tipik kimlikler ve mesaj türleri (tüm tamsayı türleri) dışında gerçek mesaj metnini VARCHAR veya TEXT olarak kaydetmem gerekiyor. 3000 karakterlik bir ön uç sınırı ayarlıyorum, bu da mesajların db'ye asla bundan daha uzun eklenmeyeceği anlamına geliyor.

VARCHAR (3000) veya METİN ile devam etmenin bir mantığı var mı? Sadece VARCHAR (3000) yazmayla ilgili bir şekilde karşı sezgisel bir şey var. Stack Overflow ile ilgili diğer benzer yayınlardan geçtim, ancak bu tür ortak mesaj depolamaya özgü görünümler elde etmek iyi olurdu.


27
Biraz yaşlı, ama buraya geldim çünkü beni bu konuda düşündüren bir sorunla karşılaştım. Benim durumumda ön uç formum 2.000 karakterle sınırlıydı, ancak depolama yöntemimdeki örtük kodlama uluslararası karakterleri birden fazla karakter olarak kodladı (görünüşte karakter başına 3 - 12 arasında herhangi bir yerde olabilir). Böylece 2.000'im aniden 24.000'e çıkıyor. Düşünülmesi gereken bir şey ...
James S

3
Metnin birçok eşzamanlı kesici uç için önemli ölçüde daha hızlı olduğunu gördüm.
Ray

1
@JamesS: utf8mb4 ...>. <
bölünmez

10
@RickJames soruyu kapatmak yerine güncellenmiş bir cevap göndermeyi düşünüyor
Yvette

3
@YvetteColomb - Bir Cevap ekledim. Esasen Kabul Edilmiş Cevaptan kurtulmak istiyorum çünkü güncel değil . Soru ve Cevaplara geldim çünkü birisi yanlış bilgi veriyor, "754 upvotes, bu yüzden doğru olmalı" diyerek. Tamam, Onaylanmış cevabını da düzenledim. (Rağmen bu yanlış geliyor.)
Rick James

Yanıtlar:


811
  • TEXTve BLOB edebilir göre tablosu, gerçek depolama konumunu gösteren bir işaretçi sahip masadan saklanır. Depolandığı yer, veri boyutu, sütun boyutu, row_format ve MySQL sürümü gibi birçok şeye bağlıdır.

  • VARCHARtablo ile yerinde saklanır. VARCHARboyutu makul olduğunda daha hızlıdır, bunun daha hızlı olacağı verilerinize ve donanımınıza bağlıdır, gerçek dünya senaryosunu verilerinizle karşılaştırmak istersiniz.


148
+1: VARCHAR (satır içi depolanır) veriler sık ​​sık alınırsa (çoğu sorgu tarafından dahil edilir) genellikle daha hızlıdır. Bununla birlikte, normalde alınmayan (yani herhangi bir sorgu tarafından referans verilmeyen) büyük bir veri hacmi için, verilerin satır içinde depolanmaması daha iyi olabilir. Satır içi olarak depolanan veriler için satır boyutunda bir üst sınır vardır.
spencer7593

21
@Pacerier: "satır içi" depolamadan kaçınmanın tam yararı, bir blokta saklanabilen satır sayısındaki artıştır, bu da tablo satırlarının InnoDB tampon önbelleğinde (daha az bellek alanı) daha az blok işgal ettiği ve daha az anlamına geldiği anlamına gelir diske ve diskten aktarılacak bloklar (azaltılmış G / Ç). Ancak, bu yalnızca "satır dışı" olarak saklanan sütunların sorgular tarafından büyük ölçüde belirtilmemiş olması durumunda bir performans avantajı olur. Bu "satır dışı" sütunlarına çoğu sorgu tarafından başvurulursa, bu yarar büyük ölçüde buharlaşır. Sütunlar maksimum satır boyutuna sığıyorsa ve sıkça başvuruluyorsa satır içi tercih edilir.
spencer7593

231
Msgstr "Boyut makul olduğunda VARCHAR daha hızlıdır". "Makul" karakter sayısı 100 nedir? 1000? 100,000?
tim peterson

125
Bu cevap InnoDB için doğru değil. Belirli bir satırdaki değer sayfa boyutuna uyuyorsa (VARCHAR ve BLOB / TEXT) diğer sütunlarla birlikte saklanır (16KB ve her sayfanın en az iki satır içermesi gerekir). Dize bunun için çok büyükse, ek sayfalara taşar. Ayrıntılı bir açıklama için bkz. Mysqlperformanceblog.com/2010/02/09/blob-storage-in-innodb .
Bill Karwin

14
@BillKarwin ... Doğru anlıyorsam , küçük metin öğeleri için InnoDB varcharve blob/ textüzerinde hiçbir performans farkı olmamalı mı? Yani o zaman sadece her yapmak akıllıca olacaktır varcharbir texttürünü ve DB satır içi vs taşması yönetmesine izin?
ryvantage

473

Kullanıcı girişinin ne kadar olacağını tahmin edebilir misiniz?

VARCHAR (X)

Vaka: kullanıcı adı, e-posta, ülke, konu, şifre


METİN

Durum: mesajlar, e-postalar, yorumlar, biçimlendirilmiş metin, html, kod, resimler, bağlantılar


MEDIUMTEXT

Vaka: büyük json cisimleri, kısa ve orta uzunlukta kitaplar, csv dizeleri


LONGTEXT

Durum: ders kitapları, programlar, yıllarca günlük dosyaları, harry potter ve ateş kadehi, bilimsel araştırma kaydı


7
Öngörülebilirlik gerçekten burada bir yan öğedir. Aslında belirleyici faktör olması gereken maksimum beklenen uzunluk. Daha öngörülebilir olarak bahsettiğiniz öğeler , diğerlerinden daha kısa oldukları için yalnızca bu şekilde .
Andrew Barber

29
@ andrew-barber Bu benim açımdan. Diğer tüm yayınlar, farklılıklar hakkında iyi açıklar, ancak ikisi arasında bir seçim yapmanız gereken durumlar hakkında değil. Tahmin edebilecek kadar kısa için varchar kullanarak iyi bir seçim olduğunu ve metin keyfi olarak uzun kullanmak iyi bir seçim olduğunu belirtmeye çalışıyordum.
Michael J. Calkins

1
Tüm sütunlar kısa ve öngörülebilirse (ör: MAC adresi, IMEI, vb ... hiçbir zaman değişmeyen şeyler) CHAR sütunlarını kullanın ve satır boyutunuzu sabit yapabilirsiniz, bu da MyISAM'ı kullanırken işleri önemli ölçüde hızlandırır. Ayrıca InnoDb rağmen emin değilim.
Matt

1
@ MichaelJ.Calkins MySQL 5.6'da olan şey. Artık InnoDB'de tam metin araması da var. Bkz. Dev.mysql.com/doc/refman/5.6/tr/fulltext-search.html
PhoneixS

7
Karakter sınırları: TINYTEXT: 255; METİN: 65,535; MEDIUMTEXT: 16,777,215; LONGTEXT: 4,294,967,29.
Victor Stoddard

218

En iyi uygulamayı netleştirmek için:

  1. Metin biçimindeki mesajlar neredeyse her zaman TEXT olarak depolanmalıdır (sonuç olarak keyfi olarak uzun olur)

  2. Dize nitelikleri VARCHAR (hedef kullanıcı adı, konu vb.) Olarak saklanmalıdır.

Ön uç sınırınız olduğunu anlıyorum. * sırıtma * Hile DB onu bağlanan uygulamalardan ayrı olarak düşünmektir. Bir uygulamanın verilere bir sınır koyması, verilerin kendiliğinden sınırlı olduğu anlamına gelmez.

Mesajların kendileri hakkında onları asla 3000 karakterden fazla olmaya zorlayan şey nedir? Bu yalnızca rastgele bir uygulama kısıtlamasıysa (örneğin, bir metin kutusu veya benzeri bir şey için) TEXTveri katmanında bir alan kullanın .


"Olmadan harika olan" ne anlama geliyor? "Değil" ne anlama geliyor?
Pacerier

7
@Pacerier James'in büyük olasılıkla “değil” örneğini vermek için: Örneğin, yakın zamana kadar PM'lerde 140 karakter sınırlaması olan Twitter'ı ele alalım. Artık mantıklı olmadığına karar verdiler ve bu sınırı tamamen kaldırmayı seçtiler. Bunu önceden düşünmemiş olsaydı (ki muhtemelen yaptıklarından eminim ...) yukarıda özetlenen senaryoya koşarlardı.
PaulSkinner

9
Sadece yeni veritabanımızı hazırlıyorum ve hiç kimsenin küçük yorum kutularımıza 2000'den fazla karakter koyamayacağını ve daha sonra James'in not ettiği gibi, bu gece aniden "iyi olmadığını" varsaymıştım. 2600 karakter uzunluğunda çok geçerli bir yorum. Bundan daha uzun sürmeyeceğini düşünerek varchar (2000) kullandım ve yanılmışım. yani evet, öyle olmasa da harika. Bizim durumumuzda tezahür etmesi sadece birkaç gün sürdü. Aşağıdaki kural Michael J. Calkins, sanırım bundan sonra kullanacağım. mesajlar, yorumlar için metin.
Lizardx

1
@Pacerier "harika olmayana kadar harika". Başka bir deyişle, neredeyse her zaman çalışır ve harikadır ... o kadar büyük olmadığı istisnai durumlar hariç.
Sınırlı Kefaret

@Pacerier, seçilen cevabın yorumlarında ilginç bir başka örnekten bahsediliyor, temelde 2000 karakterlik bir ön uç sınırı vardı, ancak tanıtılan karakterler gerçekte normal harflerden daha fazla bayt kullanılan bir kod sayfasındaydı, veritabanı boş yere ihtiyaç duyuyordu 24k karakter için, tanıtılan karakterlerin gerçek bayt boyutunu hesaba katması gerektiğinden.
RaptorX

32

Feragatname: Ben bir MySQL uzmanı değilim ... ama bu konudaki anlayışım.

Sanırım TEXT mysql satır dışında saklanırken, sanırım VARCHAR satır bir parçası olarak saklanır. Mysql satırları için maksimum satır uzunluğu vardır .. böylece VARCHAR'ı kullanarak bir satırda ne kadar başka veri depolayabileceğinizi sınırlayabilirsiniz.

Ayrıca VARCHAR'ın satırın bir parçasını oluşturması nedeniyle, bu alana bakan sorguların bir METİN parçası kullananlardan biraz daha hızlı olacağından şüpheleniyorum.


38
Satır uzunluğu sınırı 65.535 bayttır [ dev.mysql.com/doc/refman/5.0/en/column-count-limit.html ]. Sütununuz utf8 kodluysa, 3000 karakterlik bir varcharsütun 9000 bayta kadar çıkabilir.
Jan Fabry

7
UTF-8 karakterleri 4 bayta kadar olabilir, bu yüzden 12.000 bayt demek istediğinizi düşünüyorum (burada anlamadığım bazı MySQL şey olmadığı sürece).
raylu

13
@raylu MySQL'in UTF-8'i, maksimum karakter başına yalnızca 3 baytı desteklediği için "sahte UTF-8" dir, bu nedenle Unicode karakterleri MySQL'in UTF-8'inde BMP düzleminin ötesinde doğrudan saklamanın bir yolu yoktur. Bu MySQL 5.5 ile giderilmiştir.
Pacerier

2
Bu iddianın sadece MyISAM için geçerli olduğuna inanıyorum. Kesin bir kaynak bulamıyorum, ancak InnoDB'nin TEXTtablodaki satır içi mağazalarının da satıldığına inanıyorum .
dotancohen

2
@dotancohen Burada InnoDB kullanarak değişken uzunluktaki verilerin depolanmasının değişebileceğini açıklayan bir kaynak buldum (harici olarak veya satır içinde satır içi saklanabilir) mysqlserverteam.com/externally-stored-fields-in-innodb
KiX Ortillan

30

Kısa cevap: Pratik, performans veya depolama, fark yok.

Uzun cevap:

(MySQL'de) ve VARCHAR(3000)(veya başka bir büyük limit) ile arasında hiçbir fark yoktur TEXT. Birincisi 3000 karakterle kesilecek ; İkincisi 65535 de keser bayt . ( Bir karakter birden çok bayt alabileceğinden baytlar ve karakterler arasında bir ayrım yaparım .)

Daha küçük sınırlar için VARCHAR, bazı avantajlar vardır TEXT.

  • "daha küçük", sürüme, bağlama ve bağlı olarak 191, 255, 512, 767 veya 3072 vb. anlamına gelir CHARACTER SET.
  • INDEXesbir sütunun ne kadar büyük dizine eklenebileceği ile sınırlıdır. (767 veya 3072 bayt ; bu sürüme ve ayarlara bağlıdır)
  • Kompleks tarafından oluşturulan ara tablolar SELECTsiki farklı şekilde ele alınır: BELLEK (daha hızlı) veya MyISAM (daha yavaş). 'Büyük' ​​sütunlar söz konusu olduğunda, daha yavaş teknik otomatik olarak seçilir. (8.0 sürümünde yapılan önemli değişiklikler; dolayısıyla bu madde işareti değişebilir.)
  • Önceki öğeyle ilgili olarak, tüm TEXTveri türleri (aksine VARCHAR) doğrudan MyISAM'e atlar. Yani, TINYTEXToluşturulan geçici tablolar için otomatik olarak eşdeğerden daha kötüdür VARCHAR. (Ama bu tartışmayı üçüncü bir yöne götürüyor!)
  • VARBINARYgibidir VARCHAR; BLOBgibidir TEXT.

Diğer cevaplara tekabül

Orijinal soru bir şey sordu (hangi veri tipinin kullanılacağı); kabul edilen cevap başka bir şeye cevap verdi (kayıt dışı depolama). Bu cevap şimdi güncel değil.

Bu iş parçacığı başlatıldığında ve yanıtlandığında, InnoDB'de yalnızca iki "satır biçimi" vardı. Kısa süre sonra, iki biçim daha ( DYNAMICve COMPRESSED) tanıtıldı.

İçin depolama yeri TEXTve VARCHAR()dayanmaktadır boyutu değil üzerinde, veri türü adı . Bir İçin güncellenmiş büyük metin / damla sütun açık / kapalı-kayıt depolama tartışma, bkz bu .


1
Burada iyi bir fikir. Bu kabul edilen cevap olmalı.
Kosta Kontos

2
@KostaKontos - Övgü ve yazım hatası düzeltmesi için teşekkürler. Daha iyi bir cevaba ihtiyaç duyduğumda, 8 yıl ve 800 upvotes çok geç olsa bile bir cevap ekleyeceğim.
Rick James

7

Önceki cevaplar ana problem üzerinde yeterince ısrar etmiyor: çok basit sorgularda bile

(SELECT t2.* FROM t1, t2 WHERE t2.id = t1.id ORDER BY t1.id) 

geçici bir tablo gerekebilir ve bir VARCHARalan varsa CHAR, geçici tablodaki bir alana dönüştürülür . Yani tablonuzda bir VARCHAR(65000)alan ile 500 000 satır varsa , bu sütun tek başına 6.5 * 5 * 10 ^ 9 bayt kullanır. Bu tür geçici tablolar bellekte işlenemez ve diske yazılır. Etkinin felaket olması beklenebilir.

Kaynak (metriklerle): https://nicj.net/mysql-text-vs-varchar-performance/ (Bu, TEXTvs'nin VARCHAR"standart" (?) MyISAM depolama motorunda ele alınmasını ifade eder . Diğerlerinde farklı olabilir, örneğin, InnoDB.)


3
InnoDB: Aynı şey 5.7 sürümü için de geçerlidir. 8.0 ile, varchar sıcaklıkları değişken uzunluktadır.
Rick James

3

Bir yoktur BÜYÜK VARCHAR ve METİN arasındaki fark. VARCHAR alanları dizine eklenebilirken, TEXT alanları eklenemez. VARCHAR türü alanlar TEXT çevrimdışı depolanırken satır içi olarak saklanır, yalnızca TEXT verilerine işaretçiler kayıtlarda saklanır.

Alanınızı daha hızlı arama için dizine eklemeniz gerekiyorsa, ne kadar büyük olursa olsun, VARCHAR için olduğundan daha fazla güncelleme yapın veya güncelleyin. VARCHAR (10000000) hiçbir zaman METİN alanı ile aynı olmayacaktır çünkü bu iki veri türü doğası gereği farklıdır.

  • Alanınızı yalnızca arşivleme için kullanıyorsanız
  • veri hızı rekabeti umrunda değil
  • hızı önemsiyorsunuz ancak arama sorgunuzda '% LIKE%' operatörünü kullanacaksınız, böylece dizin oluşturma çok yardımcı olmayacak
  • veri uzunluğu sınırını tahmin edemezsiniz

METİN için gitmekteyiz.


Kısmen yanıltıcı bilgi: TEXT sütunlarının tamamı dizin oluşturulamaz. Dizine TEXT sütunu eklediğinizde uzunluğu belirtmeniz gerekir. Ayrıca VARCHAR'lar, 255'ten büyük olan VARCHAR'lar durumunda kendi dizinlerinde endekslenemez.
eRadical

2

Varchar, e-posta adresleri gibi küçük veriler için, Metin ise haber makaleleri, resimler gibi ikili veriler için Blob gibi çok daha büyük veriler içindir.

Varchar'ın performansı daha güçlüdür çünkü tamamen bellekten çalışır, ancak varchar(4000)örneğin veri çok büyükse durum böyle olmaz .

Öte yandan, metin belleğe yapışmaz ve disk performansından etkilenir, ancak metin verilerini ayrı bir tabloda ayırarak ve metin verilerini almak için sol birleştirme sorgusu uygulayarak bunu önleyebilirsiniz.

Blob çok daha yavaştır, bu yüzden 10000 görüntü gibi çok fazla veriye sahip değilseniz kullanın, bu da 10000 kayda mal olacaktır.

Maksimum hız ve performans için şu ipuçlarını izleyin:

  1. Ad, başlıklar, e-postalar için varchar kullanın

  2. Büyük veriler için Metin kullanma

  3. Farklı tablolardaki metni ayırma

  4. Telefon numarası gibi bir kimlikte Sol Birleştirme sorgularını kullanma

  5. Blob'u kullanacaksanız Metin ile aynı ipuçlarını uygulayın

Bu, 10 M'den büyük veri ve 10 GB'a kadar boyut garantisi olan tablolarda sorguların milisaniye maliyetini sağlayacaktır.

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.