PostgreSQL: Metin ve varchar arasındaki fark (karakter değişir)


619

textVeri türü ile character varying( varchar) veri türleri arasındaki fark nedir ?

Belgelere göre

Uzunluk belirleyici olmadan karakter değişkeni kullanılırsa, tür herhangi bir boyuttaki dizeleri kabul eder. İkincisi bir PostgreSQL oluşumudur.

ve

Buna ek olarak, PostgreSQL, herhangi bir uzunlukta dizeleri saklayan metin türünü sağlar. Yazı metni SQL standardında olmasa da, diğer bazı SQL veritabanı yönetim sistemleri de buna sahiptir.

Peki fark nedir?

Yanıtlar:


745

Fark yok, kaputun altında hepsi var varlena( değişken uzunluk dizisi ).

Bu makaleyi Depesz'den kontrol edin: http://www.depesz.com/index.php/2010/03/02/charx-vs-varcharx-vs-varchar-vs-text/

Bir kaç önemli nokta:

Hepsini özetlemek için:

  • char (n) - değerlerden daha kısa değerlerle uğraşırken çok fazla yer kaplar n(onları doldurur n) ve sondaki boşluklar eklenmesi nedeniyle küçük hatalara neden olabilir, ayrıca sınırı değiştirmek sorunludur
  • varchar (n) - canlı ortamdaki sınırı değiştirmek sorunludur (tabloyu değiştirirken özel kilit gerektirir)
  • varchar - tıpkı metin gibi
  • metin - benim için bir kazanan - üzerinde (n) veri türleri çünkü sorunları yok ve varchar üzerinde - farklı bir adı var

Makale, tüm 4 veri türü için kesici uçların ve seçimlerin performansının benzer olduğunu göstermek için ayrıntılı testler yapmaktadır. Ayrıca, gerektiğinde uzunluğu kısıtlamanın alternatif yollarına ayrıntılı bir şekilde bakar. Fonksiyona dayalı kısıtlamalar veya alanlar, uzunluk kısıtlamasının anında artması avantajını sağlar ve dize uzunluğu kısıtlamasının azaltılmasının nadir olduğu temelinde, depesz bunlardan birinin uzunluk sınırı için genellikle en iyi seçim olduğu sonucuna varır.


58
@axiopisty Harika bir makale. "Makalenin kapanması durumunda bazı alıntılar yapabilir misin?" Makalenin içeriğini / sonuçlarını kısaca özetlemeye çalıştım. Umarım endişelerinizi hafifletmek için bu yeterlidir.
jpmc26

34
@axiopisty, kesinlikle, ilk cevap " kaputun altında hepsi varlena " diyordu , ki bu cevabı sadece bağlantıdan gelen bir cevaptan ayıran kesinlikle yararlı bir bilgidir.
Bruno

24
Sınırsız bir ip ile akılda tutulması gereken bir şey, kötüye kullanım potansiyelini açmalarıdır. Bir kullanıcının soyadı herhangi bir boyutta olmasına izin verirseniz, soyadı alanınızda BÜYÜK miktarda bilgi depolayan birisine sahip olabilirsiniz. Reddit'in gelişimi hakkında bir makalede , "Her şeye bir sınır koy" tavsiyesini veriyorlar.
Mark Hildreth

7
@MarkHildreth İyi bir nokta, ancak bu tür kısıtlamalar bu günlerde bir uygulamada daha da zorlanıyor - böylece kurallar (ve ihlal / deneme girişimleri) kullanıcı arayüzü tarafından sorunsuz bir şekilde ele alınabiliyor. Birisi hala veritabanında bu tür bir şey yapmak istiyorsa kısıtlamaları kullanabilir. Bkz. Blog.jonanin.com/2013/11/20/postgresql-char-varchar " VARCHAR'dan daha fazla esnekliğe sahip alanlar oluşturmak için METİN ve kısıtlamaları kullanma örneği".
Ethan

4
@Ethan blog.jonanin.com/2013/11/20/postgresql-char-varchar -> Bu çalışmıyor, ancak burada archive.is/6xhA5 bulundu .
MrR

115

Belgelerdeki " Karakter Tipleri " nin işaret ettiği varchar(n)gibi char(n),, ve texthepsi aynı şekilde saklanır. Tek fark, eğer verilirse uzunluğu kontrol etmek için ekstra döngülere ve dolgu için gerekli ise ekstra alan ve süreye ihtiyaç duyulmasıdır char(n).

Ancak, yalnızca tek bir karakteri depolamanız gerektiğinde, özel türü kullanmanın küçük bir performans avantajı vardır "char"(çift tırnak işaretlerini saklayın - bunlar tür adının bir parçasıdır). Alana daha hızlı erişim elde edersiniz ve uzunluğu saklamak için ek yük yoktur.

Küçük "char"harfli alfabeden seçilen 1.000.000 rastgele bir tablo yaptım . Bir frekans dağılımı ( select count(*), field ... group by field) elde etmek için kullanılan bir sorgu, bir textalan kullanarak aynı verilerde yaklaşık 650 milisaniye, yaklaşık 760 alır .


18
teknik olarak tırnak işaretleri tür adının bir parçası değildir. bunu char anahtar kelimesinden ayırmak için gereklidir.
Jasen

31
Teknik olarak haklısın @Jasen ... Tabii ki, en doğru olan budur
JohannesH

veri türü "char" değil char?? Bugünlerde PostgreSQL 11+ için geçerli mi? ... Evet: "Tür "char"(tırnak işaretlerini not edin) char (1) 'den farklıdır, çünkü yalnızca bir bayt depolama alanı kullanır. Sistem kataloglarında dahili olarak basit bir numaralandırma türü olarak kullanılır ." , kılavuz / veri türü karakteri .
Peter Krauss

63

2016 İÇİN GÜNCELLEME TEZGAHLARI (pg9.5 +)

Ve "saf SQL" karşılaştırmaları kullanmak (harici komut dosyası olmadan)

  1. UTF8 ile herhangi bir string_generator kullanın

  2. ana kriterler:

    2.1. INSERT

    2.2. Karşılaştırma ve saymayı SEÇ


CREATE FUNCTION string_generator(int DEFAULT 20,int DEFAULT 10) RETURNS text AS $f$
  SELECT array_to_string( array_agg(
    substring(md5(random()::text),1,$1)||chr( 9824 + (random()*10)::int )
  ), ' ' ) as s
  FROM generate_series(1, $2) i(x);
$f$ LANGUAGE SQL IMMUTABLE;

Spesifik test hazırlayın (örnekler)

DROP TABLE IF EXISTS test;
-- CREATE TABLE test ( f varchar(500));
-- CREATE TABLE test ( f text); 
CREATE TABLE test ( f text  CHECK(char_length(f)<=500) );

Temel bir test yapın:

INSERT INTO test  
   SELECT string_generator(20+(random()*(i%11))::int)
   FROM generate_series(1, 99000) t(i);

Ve diğer testler,

CREATE INDEX q on test (f);

SELECT count(*) FROM (
  SELECT substring(f,1,1) || f FROM test WHERE f<'a0' ORDER BY 1 LIMIT 80000
) t;

... ve kullanın EXPLAIN ANALYZE.

TEKRAR GÜNCELLEME 2018 (pg10)

2018'in sonuçlarını eklemek ve önerileri güçlendirmek için küçük bir düzenleme yapın.


2016 ve 2018 sonuçları

Ortalamamdan sonra, birçok makinede ve birçok testte sonuçlarım: hepsi aynı
(istatistiksel olarak daha az tham standart sapma).

Öneri

  • Kullanım text, veri türü
    eski önlemek varchar(x)bazen standart, örneğin olmadığından CREATE FUNCTIONmaddeleri varchar(x)varchar(y) .

  • (Aynı ile sınırlarını ifade varcharperformans!) ile tarafından CHECKyan tümcesi CREATE TABLE
    örneğin CHECK(char_length(x)<=10).
    Aşağıdakileri de yapabilirsiniz kontrol aralıkları ve dize yapısı için INSERT / UPDATE performans ihmal edilebilir kaybı ile
    örCHECK(char_length(x)>5 AND char_length(x)<=20 AND x LIKE 'Hello%')


Yani tüm sütunlarımı metin yerine varchar yaptığım önemli değil mi? 5 karakter ve kesinlikle 255. - Biraz sadece 4 olmasına rağmen uzunluğunu belirtmedi
siper

1
@ trençkot evet, önemli değil
FuriousFolder

1
Havalı, güvenli olmasını sağladım ve her şeyi yine de yazdım. İyi çalıştı ve yine de milyonlarca tarihi kayıt eklemek çok kolaydı.
hendek

@ siper ve okuyucu: tek istisna daha hızlı veri tipidir "char", yani charbugünlerde PostgreSQL 11+ bile değildir . Gibi rehber / veri türü karakterli diyor "tipi "char"(tırnak unutmayın) sadece depolama biri bayt kullandığı char (1) farklıdır. Bu içten bir sistem kataloglarında kullanılan basit numaralandırma türü ." .
Peter Krauss

3
2019'da pg11 ile hala geçerli: text> varchar (n)> text_check> char (n)
Olivier Refalo

37

PostgreSQL kılavuzunda

Bu üç tür arasında, boş dolgulu türü kullanırken artan depolama alanı ve uzunluk kısıtlı bir sütuna depolarken uzunluğu kontrol etmek için birkaç ekstra CPU döngüsü dışında hiçbir performans farkı yoktur. Karakter (n) diğer bazı veritabanı sistemlerinde performans avantajlarına sahip olsa da, PostgreSQL'de böyle bir avantaj yoktur; aslında karakter (n) ek depolama maliyetleri nedeniyle genellikle üçün en yavaş olanıdır. Çoğu durumda metin veya karakter değiştirme kullanılmalıdır.

Genellikle metin kullanırım

Kaynaklar: http://www.postgresql.org/docs/current/static/datatype-character.html


23

Bence, varchar(n)kendi avantajları var. Evet, hepsi aynı altta yatan türü kullanıyorlar. Ancak, PostgreSQL'deki dizinlerin satır başına 2712 bayt boyut sınırına sahip olduğuna dikkat edilmelidir .

TL; DR: Eğer kullanırsanız texttürü bir kısıtlama olmaksızın ve bu sütunlardan endeksler var, Sütunlarınızdan bazıları için bu sınıra ve verileri eklemek çalışıyorum ama kullanarak zaman hata alıyorum çok mümkündür varchar(n), bunu önleyebilirsiniz.

Bazı ayrıntılar: Buradaki sorun, PostgreSQL'in texttür için dizin oluştururken veya 2712'den büyük varchar(n)yerlerde herhangi bir istisna nvermemesidir. Ancak, sıkıştırılmış boyutu 2712'den büyük olan bir kayıt eklenmeye çalışıldığında hata verecektir. Bu, tekrarlayan karakterlerden oluşan 100.000 karakter dizisini kolayca ekleyebileceğiniz anlamına gelir, çünkü 2712'nin çok altında sıkıştırılacaktır, ancak sıkıştırılmış boyut 2712 bayttan büyük olduğu için 4000 karakter içeren bir dize ekleyemeyebilirsiniz. 2712'den çok daha büyük olmayan varchar(n)yerlerde kullanmak , bu hatalardan güvende olursunuz.n


Daha sonra metin için indeksleme oluşturmaya çalışırken postgres hataları sadece varchar ((n) içermeyen sürüm) için çalışır. Sadece gömülü postgres ile test edildi.
arntg

2
: Atıfta stackoverflow.com/questions/39965834/... PostgreSQL Wiki bir bağlantı vardır: wiki.postgresql.org/wiki/... benzediğini satır başına belirtti 2.712 bayt sınırı yanlıştır gelen, 400GB olarak maksimum Satır boyutuna sahip . Bir veritabanı için maksimum boyut? sınırsız (32 TB veritabanı var) Bir tablo için maksimum boyut? 32 TB Bir satırın maksimum boyutu? 400 GB Bir alan için maksimum boyut? 1 GB Bir tablodaki maksimum satır sayısı? sınırsız
Bill Worthington

@ BillWorthington Gönderdiğiniz numaralar, dizinleri koymayı hesaba katmaz. 2712 bayt btree'nin maksimum sınırlarıyla ilgilidir, bu bir doküman detayında bulamayacağınız bir uygulama detayıdır. Ancak, kolayca kendiniz test edebilir veya sadece "postgresql dizin satır boyutu dizin için maksimum 2712 aşıyor" arayarak google örneğin.
18'de

PostgeSQL'de yeniyim, bu yüzden uzman değilim. Haber makalelerini tablodaki bir sütunda saklamak istediğim bir proje üzerinde çalışıyorum. Metin sütun türü kullanacağım gibi görünüyor. Toplam 2712 bayt satır boyutu, Oracle ile aynı seviyeye yakın olduğu düşünülen bir veritabanı için çok düşük geliyor. Büyük bir metin alanını dizine eklemekten bahsettiğinizi doğru anladım mı? Sana meydan okumaya ya da tartışmaya değil, sadece gerçek sınırları anlamaya çalışıyor. Eğer herhangi bir endeks yoksa, o zaman satır sınırı wiki gibi 400GB olurdu ?? Hızlı yanıtın için teşekkürler.
Bill Worthington

1
@BillWorthington Tam Metin Arama hakkında araştırma yapmalısınız. Bu bağlantıyı kontrol edin örn.
sotn

18

metin ve varchar, farklı örtük tür dönüşümlerine sahiptir. Fark ettiğim en büyük etki, arka boşlukların ele alınması. Örneğin ...

select ' '::char = ' '::varchar, ' '::char = ' '::text, ' '::varchar = ' '::text

beklediğiniz gibi true, false, truedeğil döner true, true, true.


Bu nasıl mümkün olabilir? A = b ve a = c ise b = c olur.
Lucas Silva

4

Biraz OT: Rails kullanıyorsanız, web sayfalarının standart biçimlendirmesi farklı olabilir. Veri giriş formları için textkutular kaydırılabilir, ancak character varying(Raylar string) kutuları tek satırlıdır. Gösteri görünümleri gerektiği kadar.


2

Http://www.sqlines.com/postgresql/datatypes/text adresinden iyi bir açıklama :

TEXT ve VARCHAR (n) arasındaki tek fark, bir VARCHAR sütununun maksimum uzunluğunu sınırlayabilmenizdir, örneğin, VARCHAR (255) 255 karakterden uzun bir dize eklenmesine izin vermez.

Hem TEXT hem de VARCHAR 1 Gb'de üst limite sahiptir ve aralarında performans farkı yoktur (PostgreSQL belgelerine göre).


-1

character varying(n), varchar(n)- (Her ikisi de aynı). değer, bir hata yükseltilmeden n karaktere kısaltılacaktır.

character(n), char(n)- (Her ikisi de aynı). sabit uzunlukta ve uzunluğun sonuna kadar boşluklarla doldurulur.

text- Sınırsız uzunluk.

Misal:

Table test:
   a character(7)
   b varchar(7)

insert "ok    " to a
insert "ok    " to b

Sonuçları alıyoruz:

a        | (a)char_length | b     | (b)char_length
----------+----------------+-------+----------------
"ok     "| 7              | "ok"  | 2

5
Değer sütun boyutunu aştığında MySQL verileri sessizce kesecek olsa da, PostgreSQL bir "karakter türü (n) tipi karakteri için çok uzun bir değer" hatası vermeyecek ve yükseltmeyecektir.
gsiems
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.