Kinerja indeks untuk CHAR vs VARCHAR (Postgres)

15

Dalam jawaban ini ( /programming/517579/strings-as-primary-keys-in-sql-database ) satu komentar menarik perhatian saya:

Juga perlu diingat bahwa sering ada perbedaan yang sangat besar antara CHAR dan VARCHAR saat melakukan perbandingan indeks

Apakah ini berlaku / masih berlaku untuk Postgres?

Saya menemukan halaman-halaman di Oracle yang mengklaim CHARlebih atau kurang alias VARCHARdan karena itu kinerja indeksnya sama, tetapi saya tidak menemukan apa pun yang pasti di Postgres.

LetMeSOThat4U
sumber

Jawaban:

24

CHARdan VARCHARdiimplementasikan persis sama di Postgres (dan Oracle). Tidak ada perbedaan dalam kecepatan saat menggunakan tipe data tersebut.

Namun, ada satu perbedaan yang dapat membuat perbedaan dalam kinerja: charkolom selalu diisi dengan panjang yang ditentukan. Jadi jika Anda mendefinisikan kolom sebagai char(100)dan satu sebagai varchar(100)tetapi hanya menyimpan 10 karakter di masing-masing, char(100)kolom menggunakan 100 karakter untuk setiap nilai (10 karakter yang Anda simpan, ditambah 90 spasi), sedangkan varcharkolom hanya menyimpan 10 karakter.

Membandingkan 100 karakter dengan 100 karakter akan lebih lambat daripada membandingkan 10 karakter dengan 10 karakter - meskipun saya ragu Anda benar-benar dapat mengukur perbedaan ini dalam query SQL.

Jika Anda mendeklarasikan keduanya dengan panjang 10 karakter dan selalu menyimpan tepat 10 karakter di dalamnya, maka sama sekali tidak ada perbedaan apa pun (ini berlaku untuk Oracle dan Postgres)

Jadi satu-satunya perbedaan adalah padding yang dilakukan untuk chartipe data.


Juga perlu diingat bahwa sering ada perbedaan yang sangat besar antara CHAR dan VARCHAR saat melakukan perbandingan indeks

Kutipan di atas hanya benar jika (dan hanya jika) charkolom didefinisikan terlalu lebar (yaitu Anda membuang-buang ruang karena padding). Jika panjang charkolom selalu digunakan sepenuhnya (jadi tidak ada bantalan terjadi), maka kutipan di atas salah (setidaknya untuk Postgres dan Oracle)


Dari sudut pandang saya, chartipe data tidak benar-benar memiliki penggunaan kata nyata. Cukup gunakan varchar(atau textdi Postgres) dan lupakan yang charada.

seekor kuda tanpa nama
sumber
2
Membandingkan 100 karakter dengan 100 karakter akan lebih lambat daripada membandingkan 10 karakter dengan 10 karakter - meskipun saya ragu Anda benar-benar dapat mengukur perbedaan ini dalam permintaan SQL. - Bergantung pada apa yang kueri lakukan selain mengurutkan, perbedaannya bisa sangat besar. Itu sebabnya Postgres 9.5 memiliki fitur "kunci disingkat" baru: pgeoghegan.blogspot.de/2015/01/...
chirlu
6

Saya setuju dengan semua yang dikatakan oleh a_horse_with_no_name, dan saya umumnya setuju dengan saran komentar Erwin:

Tidak, char lebih rendah (dan ketinggalan jaman). teks dan varchar melakukan (hampir) sama.

Metadata

Dengan satu pengecualian kecil, satu - satunya waktu yang saya gunakan char()adalah ketika saya ingin meta-data mengatakan ini HARUS memiliki x-karakter. Meskipun saya tahu bahwa char()hanya mengeluh jika inputnya melebihi batas, saya akan sering melindungi dari underruns dalam CHECKkendala. Sebagai contoh,

CREATE TABLE foo (
  x char(10) CHECK ( length(x) = 10 )
);
INSERT INTO foo VALUES (repeat('x', 9));

Saya melakukan ini karena beberapa alasan,

  1. char(x)kadang-kadang disimpulkan dengan skema-loader sebagai kolom dengan lebar tetap. Ini mungkin membuat perbedaan dalam bahasa yang dioptimalkan untuk string dengan lebar tetap.
  2. Ini menetapkan konvensi yang masuk akal dan mudah ditegakkan. Saya dapat menulis skema-loader dalam bahasa untuk menghasilkan kode dari konvensi ini.

Perlu contoh di mana saya dapat melakukan ini,

  1. Singkatan dua huruf, meskipun karena daftar ini dapat disebutkan, saya biasanya akan melakukannya dengan ENUM .
  2. Nomor Identifikasi Kendaraan
  3. Nomor Model (dari ukuran tetap)

Kesalahan

Perhatikan bahwa beberapa orang mungkin merasa tidak nyaman dengan ketidaksesuaian pesan kesalahan di kedua sisi batas, tetapi itu tidak mengganggu saya

test=# INSERT INTO foo VALUES (repeat('x', 9));
ERROR:  new row for relation "foo" violates check constraint "foo_x_check"
DETAIL:  Failing row contains (xxxxxxxxx ).
test=# INSERT INTO foo VALUES (repeat('x', 11));
ERROR:  value too long for type character(10)

Kontras dengan varchar

Selain itu, saya pikir saran di atas sangat cocok dengan konvensi yang hampir selalu digunakantext . Anda bertanya tentang varchar(n)juga. Saya tidak pernah menggunakannya . Setidaknya, saya tidak ingat kapan terakhir kali saya menggunakan varchar(n).

  • Jika spec memiliki bidang lebar statis yang saya percayai, saya menggunakan char(n),
  • Kalau tidak, saya menggunakan textyang efektif varchar(tanpa batas)

Jika saya menemukan spec yang memiliki kunci teks panjang variabel yang bermakna dan saya percaya memiliki panjang maksimum konstan, saya akan menggunakan varchar(n) juga. Namun, saya tidak bisa memikirkan apa pun yang cocok dengan kriteria itu.

Catatan tambahan

Tanya Jawab terkait:

Evan Carroll
sumber
1

Postgresql

sales_reporting_db=# create table x (y char(2));
CREATE TABLE
sales_reporting_db=# insert into x values ('Y');
INSERT 0 1
sales_reporting_db=# select '*' || y || '*' from x;
 ?column? 
----------
 *Y*

Peramal

SQL> create table x ( y char(2));

Table created.

SQL> insert into x values ('Y');

1 row created.

SQL> select '*' || y || '*' from x;

'*'|
----
*Y *

Postgresql tidak pad dengan spasi.

pengguna939857
sumber
Itu hanya ilusi optik di Postgres. CobaSELECT pg_column_size(y) FROM x;
dezso
-2

Saya menemukan ini paling berguna, dan penjelasan 3 baris cepat:

Dari CHAR (n) Vs VARCHAR (N) Vs Teks Di Postgres

  • Jika Anda ingin menyimpan beberapa teks dengan panjang yang tidak diketahui, gunakan TEXTtipe data.
  • Jika Anda ingin menyimpan beberapa teks dengan panjang yang tidak diketahui, tetapi Anda tahu panjang maksimalnya, gunakan VARCHAR(n).
  • Jika Anda ingin menyimpan beberapa teks dengan panjang persis yang diketahui, gunakan CHAR(N).
Lewis
sumber