PostgreSQL: Perbedaan antara teks dan varchar (karakter bervariasi)


620

Apa perbedaan antara texttipe data dan character varying( varchar) tipe data?

Menurut dokumentasi

Jika variasi karakter digunakan tanpa penentu panjang, tipe menerima string dari ukuran apa pun. Yang terakhir adalah ekstensi PostgreSQL.

dan

Selain itu, PostgreSQL menyediakan jenis teks, yang menyimpan string dengan panjang apa pun. Meskipun jenis teks tidak dalam standar SQL, beberapa sistem manajemen database SQL lainnya juga memilikinya.

Jadi apa bedanya?

Jawaban:


746

Tidak ada perbedaan, di bawah kap itu semua varlena( array panjang variabel ).

Periksa artikel ini dari Depesz: http://www.depesz.com/index.php/2010/03/02/charx-vs-varcharx-vs-varchar-vs-text/

Beberapa highlight:

Singkatnya:

  • char (n) - membutuhkan terlalu banyak ruang ketika berhadapan dengan nilai yang lebih pendek dari n(bantalannya n), dan dapat menyebabkan kesalahan halus karena menambahkan spasi tambahan, ditambah itu bermasalah untuk mengubah batas
  • varchar (n) - bermasalah untuk mengubah batas di lingkungan langsung (memerlukan kunci eksklusif saat mengubah tabel)
  • varchar - seperti halnya teks
  • teks - bagi saya pemenang - atas (n) tipe data karena tidak memiliki masalah, dan lebih dari varchar - karena memiliki nama yang berbeda

Artikel ini melakukan pengujian terperinci untuk menunjukkan bahwa kinerja menyisipkan dan memilih untuk semua 4 tipe data serupa. Ini juga membutuhkan perincian cara alternatif untuk membatasi panjang saat dibutuhkan. Batasan berbasis fungsi atau domain memberikan keuntungan peningkatan instan dari batasan panjang, dan atas dasar bahwa mengurangi batasan panjang string jarang terjadi, depesz menyimpulkan bahwa salah satu dari mereka biasanya merupakan pilihan terbaik untuk batas panjang.


58
@axiopisty Ini artikel yang bagus. Anda bisa saja berkata, "Bisakah Anda menarik beberapa kutipan kalau-kalau artikelnya turun?" Saya sudah mencoba meringkas konten / kesimpulan artikel secara singkat. Saya harap ini cukup untuk meredakan kekhawatiran Anda.
jpmc26

34
@axiopisty, sebenarnya, jawaban awal adalah "di bawah tenda itu semua varlena ", yang tentunya informasi yang berguna yang membedakan jawaban ini dari jawaban hanya tautan.
Bruno

24
Satu hal yang perlu diingat dengan string tanpa batas adalah bahwa mereka membuka potensi penyalahgunaan. Jika Anda mengizinkan pengguna untuk memiliki nama belakang ukuran apa pun, Anda mungkin meminta seseorang menyimpan informasi dalam jumlah besar di bidang nama belakang Anda. Dalam sebuah artikel tentang pengembangan reddit, mereka memberikan saran untuk "Menempatkan batas pada segalanya".
Mark Hildreth

7
@MarkHildreth Poin bagus, meskipun umumnya kendala seperti itu ditegakkan lebih jauh dalam aplikasi akhir-akhir ini - sehingga aturan (dan upaya pelanggaran / percobaan) dapat ditangani dengan lancar oleh UI. Jika seseorang masih ingin melakukan hal semacam ini dalam database mereka dapat menggunakan batasan. Lihat blog.jonanin.com/2013/11/20/postgresql-char-varchar yang mencakup "contoh penggunaan TEXT dan batasan untuk membuat bidang dengan lebih banyak fleksibilitas daripada VARCHAR".
Ethan

4
@Ethan blog.jonanin.com/2013/11/20/postgresql-char-varchar -> Ini turun, tetapi ditemukan di sini archive.is/6xhA5 .
MrR

115

Sebagai " Jenis Karakter " di poin dokumentasi keluar, varchar(n), char(n), dan textsemua disimpan dengan cara yang sama. Satu-satunya perbedaan adalah siklus tambahan diperlukan untuk memeriksa panjang, jika ada yang diberikan, dan ruang tambahan dan waktu yang dibutuhkan jika padding diperlukan untukchar(n) .

Namun, ketika Anda hanya perlu menyimpan satu karakter, ada sedikit keuntungan kinerja untuk menggunakan tipe khusus "char" (mempertahankan tanda kutip ganda - mereka adalah bagian dari nama tipe). Anda mendapatkan akses lebih cepat ke bidang, dan tidak ada overhead untuk menyimpan panjangnya.

Saya baru saja membuat tabel 1.000.000 acak yang "char"dipilih dari huruf kecil. Kueri untuk mendapatkan distribusi frekuensi ( select count(*), field ... group by field) membutuhkan sekitar 650 milidetik, vs sekitar 760 pada data yang sama menggunakan textbidang.


18
secara teknis tanda kutip bukan bagian dari nama jenis. mereka diperlukan untuk membedakannya dari kata kunci char.
Jasen

31
Secara teknis Anda benar @ Yasen ... Yang mana, tentu saja, adalah jenis terbaik yang benar
JohannesH

tipe data "char" tidak char?? Apakah ini berlaku di PostgreSQL 11+ saat ini? ... Ya: "Tipe "char"(perhatikan tanda kutip) berbeda dari char (1) karena hanya menggunakan satu byte penyimpanan. Ini digunakan secara internal dalam katalog sistem sebagai tipe enumerasi sederhana ." , panduan / tipe data-karakter .
Peter Krauss

64

MEMPERBARUI BENCHMARKS UNTUK 2016 (hal9.5 +)

Dan menggunakan tolok ukur "SQL murni" (tanpa skrip eksternal)

  1. gunakan string_generator dengan UTF8

  2. tolok ukur utama:

    2.1. MEMASUKKAN

    2.2. PILIH membandingkan dan menghitung


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;

Siapkan tes khusus (contoh)

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) );

Lakukan tes dasar:

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

Dan tes lainnya,

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;

... Dan gunakan EXPLAIN ANALYZE.

DIPERBARUI LAGI 2018 (hal 10)

sedikit edit untuk menambahkan hasil 2018 dan memperkuat rekomendasi.


Hasil pada 2016 dan 2018

Hasil saya, setelah rata-rata, di banyak mesin dan banyak tes: semua sama
(secara statistik kurang dari standar deviasi tham).

Rekomendasi

  • Gunakan texttipe data,
    hindari yang lama varchar(x)karena terkadang ini bukan standar, misalnya dalam CREATE FUNCTIONklausa varchar(x)varchar(y) .

  • menyatakan batas (dengan varcharkinerja yang sama !) dengan dengan CHECKklausa dalam CREATE TABLE
    mis CHECK(char_length(x)<=10).
    Dengan hilangnya kinerja yang dapat diabaikan dalam INSERT / UPDATE Anda juga dapat mengontrol rentang dan struktur string
    misalnyaCHECK(char_length(x)>5 AND char_length(x)<=20 AND x LIKE 'Hello%')


Jadi tidak masalah daripada saya membuat semua kolom saya varchar bukan teks? Saya tidak menentukan panjangnya meskipun beberapa hanya 4 - 5 karakter dan tentu saja tidak 255.
trench

1
@ parit ya, tidak masalah
FuriousFolder

1
keren, saya redid menjadi aman dan saya tetap membuat semuanya teks. Itu bekerja dengan baik dan itu super mudah untuk menambahkan jutaan catatan sejarah dengan cepat.
parit

@trench and reader: satu-satunya pengecualian adalah datatype yang lebih cepat "char", itu tidak char, bahkan di PostgreSQL 11+ saat ini. Sebagai panduan / datatype karakter mengatakan "Tipe "char"(perhatikan tanda kutip) berbeda dari char (1) dalam hal itu hanya menggunakan satu byte penyimpanan. Hal ini secara internal digunakan dalam katalog sistem sebagai jenis pencacahan sederhana ." .
Peter Krauss

3
masih berlaku dengan pg11 pada tahun 2019: text> varchar (n)> text_check> char (n)
Olivier Refalo

37

Pada manual PostgreSQL

Tidak ada perbedaan kinerja di antara ketiga jenis ini, selain dari peningkatan ruang penyimpanan saat menggunakan jenis yang empuk, dan beberapa siklus CPU tambahan untuk memeriksa panjang saat menyimpan ke dalam kolom yang dibatasi panjang. Sementara karakter (n) memiliki keunggulan kinerja di beberapa sistem database lain, tidak ada keunggulan seperti itu di PostgreSQL; sebenarnya karakter (n) biasanya paling lambat dari ketiganya karena biaya penyimpanan tambahan. Dalam kebanyakan situasi, variasi teks atau karakter harus digunakan sebagai gantinya.

Saya biasanya menggunakan teks

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


23

Menurut saya, varchar(n)memiliki kelebihan itu sendiri. Ya, mereka semua menggunakan tipe dasar yang sama dan semua itu. Tetapi, harus ditunjukkan bahwa indeks dalam PostgreSQL memiliki batas ukuran 2712 byte per baris.

TL; DR: Jika Anda menggunakan texttipe tanpa kendala dan memiliki indeks pada kolom ini, sangat mungkin Anda menekan batas ini untuk beberapa kolom Anda dan mendapatkan kesalahan ketika Anda mencoba memasukkan data tetapi dengan menggunakan varchar(n), Anda dapat mencegahnya.

Beberapa perincian lebih lanjut: Masalahnya di sini adalah PostgreSQL tidak memberikan pengecualian saat membuat indeks untuk texttipe atau di varchar(n)manan lebih besar dari 2712. Namun, itu akan memberikan kesalahan ketika catatan dengan ukuran terkompresi lebih besar dari 2712 dicoba untuk dimasukkan. Ini berarti bahwa Anda dapat memasukkan 100.000 karakter string yang disusun oleh karakter berulang dengan mudah karena akan dikompresi jauh di bawah 2712 tetapi Anda mungkin tidak dapat memasukkan beberapa string dengan 4000 karakter karena ukuran terkompresi lebih besar dari 2712 byte. Menggunakan varchar(n)tempat nyang tidak terlalu besar dari 2712, Anda aman dari kesalahan ini.


Kemudian kesalahan postgres ketika mencoba membuat pengindeksan untuk teks hanya berfungsi untuk varchar (versi tanpa (n)). Hanya diuji dengan postgres tertanam.
arntg

2
Mengacu pada: stackoverflow.com/questions/39965834/… yang memiliki tautan ke PostgreSQL Wiki: wiki.postgresql.org/wiki/… memiliki ukuran Row maksimum sebagai 400GB, dari yang terlihat seperti batas 2712 byte yang dinyatakan per baris salah . Ukuran maksimum untuk basis data? tidak terbatas (ada 32 TB basis data) Ukuran maksimum untuk sebuah tabel? 32 TB Ukuran maksimum untuk satu baris? 400 GB Ukuran maksimum untuk sebuah bidang? 1 GB Jumlah maksimum baris dalam sebuah tabel? tidak terbatas
Bill Worthington

@BillWorthington Angka-angka yang Anda posting tidak memperhitungkan menempatkan indeks. 2712 byte adalah tentang batas maksimum btree, ini adalah detail implementasi sehingga Anda tidak dapat menemukannya di dokumen. Namun, Anda dapat dengan mudah mengujinya sendiri atau hanya google saja dengan mencari "ukuran baris indeks postgresql melebihi maksimum 2712 untuk indeks" misalnya.
sotn

Saya baru mengenal PostgeSQL, jadi saya bukan ahli. Saya sedang mengerjakan sebuah proyek di mana saya ingin menyimpan artikel berita dalam sebuah kolom dalam sebuah tabel. Sepertinya jenis kolom teks adalah apa yang akan saya gunakan. Ukuran baris total 2.712 byte terdengar terlalu rendah untuk database yang seharusnya mendekati level yang sama dengan Oracle. Apakah saya mengerti Anda dengan benar bahwa Anda mengacu pada pengindeksan bidang teks besar? Tidak mencoba untuk menantang atau berdebat dengan Anda, hanya mencoba memahami batasan sebenarnya. Jika tidak ada indeks yang terlibat, maka apakah batas baris menjadi 400GB seperti pada wiki ?? Terima kasih atas tanggapan cepat Anda.
Bill Worthington

1
@ BillWorthington Anda harus meneliti tentang Pencarian Teks Lengkap. Lihat tautan ini misalnya
sotn

18

teks dan varchar memiliki konversi tipe implisit yang berbeda. Dampak terbesar yang saya perhatikan adalah penanganan ruang trailing. Sebagai contoh ...

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

kembali true, false, truedan tidak true, true, trueseperti yang Anda harapkan.


Bagaimana ini mungkin? Jika a = b dan a = c maka b = c.
Lucas Silva

4

Agaknya OT: Jika Anda menggunakan Rails, pemformatan standar laman web mungkin berbeda. Untuk formulir entri data, textkotak dapat digulir, tetapi kotak character varying(Rel string) adalah satu baris. Tampilkan tampilan selama diperlukan.


2

Penjelasan yang bagus dari http://www.sqlines.com/postgresql/datatypes/text :

Satu-satunya perbedaan antara TEXT dan VARCHAR (n) adalah bahwa Anda dapat membatasi panjang maksimum kolom VARCHAR, misalnya, VARCHAR (255) tidak memungkinkan memasukkan string lebih dari 255 karakter.

Baik TEXT dan VARCHAR memiliki batas atas pada 1 Gb, dan tidak ada perbedaan kinerja di antara mereka (menurut dokumentasi PostgreSQL).


-1

character varying(n), varchar(n)- (Keduanya sama). nilai akan dipotong ke n karakter tanpa menimbulkan kesalahan.

character(n), char(n)- (Keduanya sama). panjang tetap dan akan pad dengan kosong sampai akhir panjang.

text- Panjang tidak terbatas.

Contoh:

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

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

Kami mendapatkan hasil:

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

5
Sementara MySQL akan secara diam-diam memotong data ketika nilainya melebihi ukuran kolom, PostgreSQL tidak akan dan akan menaikkan "nilai terlalu lama untuk kesalahan tipe karakter yang bervariasi (n)".
gsiems
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.